Está en la página 1de 586

Apuntes

Programación Orientada a Objetos

Ing. Jorge J. Prado Delgadillo

Curso Programación Orientada a Objeto


Profesor : Ing. Jorge J. Prado D. Docente UNI
CONTENIDO

CAPITULO I: EL PARADIGMA ORIENTADO A OBJETOS

1.1 Introducción, surgimiento y desarrollo del paradigma Orientado a Objetos


1.2 Clases y Objetos
1.3 Encapsulamiento
1.4 Herencia
1.5 Polimorfismo
1.6 Sobrecarga de Operadores y Funciones
1.7. Resumen del capitulo
1.7 Ejercicios de la unidad

CAPITULO II: METODOLOGIAS DE ANÁLISIS Y DISEÑO ORIENTADO A


OBJETOS

2.1 Comparación y evaluación de las metodologías de Análisis y Diseño Orientadas a


Objetos (Metodología OMT por Rumbaugh, Análisis y Diseño Orientado a Objetos por
Graddy Booch, etc).

2.1.1 Análisis Orientado a Objetos


2.1.2 Simbología y Notación del Diseño Orientado a Objetos
2.2 Construcción de modelos utilizando alguna de las metodologías estudiadas.

CAPITULO III : LENGUAJES ORIENTADOS A OBJETOS

3.1 Comparación y evaluación de los Lenguajes Orientados a Objetos (Visual Basic, Eiffel,
Smalltalk, C++, Java, etc.).

3.2 Aplicación de un Lenguaje Orientado a Objetos. Visual Basic

3.2.1 Sintaxis General del Lenguaje


3.2.2 Desarrollo e implementación de programas usando el Lenguaje
Orientado a Objetos

CAPITULO IV : INTRODUCCION A LAS BASES DE DATOS ORIENTADAS A


OBJETOS

4.1 Bases de Datos Orientadas a Objetos


4.2 Interfaces Gráficas del usuario Orientadas a Objetos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 2


CAPITULO I: EL PARADIGMA ORIENTADO A OBJETO
1.1.- INTRODUCCIÓN, SURGIMIENTOS Y DESARROLLO DEL
PARADIGMA ORIENTADO A OBJETO

1.1.1.- Introducción

ESTRUCTURADO

LOGICO
Paradigmas
FUNCIONAL

ORIENTADO A OBJETO

El Paradigma Estructurado:

El primero de los paradigmas utilizados en el desarrollo de la ciencias de computación, este


paradigma se aplica desde los albores del desarrollo de la computación ya que permitía dar
respuesta a las limitaciones de hardware que había en ese entonces, puesto que permitía entre
otras características la realización secuencia de las instrucciones o comandos para el
computador, el desarrollo secuencial de las mismas, la elaboración en bloque de instrucciones
de los programas, lo que permitía seccionar la solución informática y aplicarlas a las
necesidades de aplicación en los computadores de ese entonces.

Este paradigma duro lo suficiente hasta que las compañías y


empresas tuvieron una explosión de sus actividades y pasaron de
ser locales a ser regionales y nacionales, aumentado su grado de
complejidad y manejo de información, este se agudizo cuando las
necesidades pasaron las fronteras de los países y las empresas
nacionales se trasformaron en compañías internacionales.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 3


La ciencia de la computación tenía que
buscar otra alternativa, y con la
aparición de nuevos productos
electrónicos (El chip de las maquinas
computadoras) que permitía enormes
velocidades de proceso y la increíble
mejora de unidades de
almacenamientos internas y externas,
así como la creación de grandes
corporaciones multinacionales, se
tenía que trabajar en nuevo
paradigma que respondiera a esta
nuevas situaciones.

Programación imperativa
La programación imperativa, en contraposición a la programación declarativa es un
paradigma de programación que describe la programación en términos del estado del
programa y sentencias que cambian dicho estado. Los programas imperativos son un
conjunto de instrucciones que le indican al computador cómo realizar una tarea.

La implementación de hardware de la mayoría de computadores es imperativa; prácticamente


todo el hardware de los computadores está diseñado para ejecutar código de máquina, que es
nativo al computador, escrito en una forma imperativa. Esto se debe a que el hardware de los
computadores implementa el paradigma de las Máquinas de Turing. Desde esta perspectiva
de bajo nivel, el estilo del programa está definido por los contenidos de la memoria, y las
sentencias son instrucciones en el lenguaje de máquina nativo del computador (por ejemplo
el lenguaje ensamblador).

Los lenguajes imperativos de alto nivel usan variables y sentencias más complejas, pero aún
siguen el mismo paradigma. Las recetas y las listas de revisión de procesos, a pesar de no ser
programas de computadora, son también conceptos familiares similares en estilo a la
programación imperativa; cada paso es una instrucción, y el mundo físico guarda el estado
(Zoom).

Los primeros lenguajes imperativos fueron los lenguajes de máquina de los computadores
originales. En estos lenguajes, las instrucciones fueron muy simples, lo cual hizo la
implementación de hardware fácil, pero obstruyendo la creación de programas complejos.
Fortran, cuyo desarrollo fue iniciado en 1954 por John Backus en IBM, fue el primer gran
lenguaje de programación en superar los obstáculos presentados por el código de máquina en
la creación de programas complejos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 4


Algunos lenguajes imperativos empezaron a surgir tales como:

ASP , BASIC, C, C# , C++, Fortran, Pascal, Java, Perl , PHP, Lua

El Paradigma lógico
El paradigma lógico está orientado a la inteligencia artificial, es difícil estimar un tiempo
exacto en la historia de la computación cuando nace este paradigma, lo que vale destacar es
que su forma de afrontar los problemas es por medio de esquemas heurísticos, es decir
tomando en cuenta esquemas definidos de búsquedas y toma de decisiones a partir de una o
varias funciones de evaluación.

En 1972, en la universidad de Marsella, Francia, y otros científicos en Edimburgo trabajaron


con un lenguaje llamado Prolog, el cual tomo auge cuando el gobierno japonés lo designo
como lenguaje oficial de desarrollos de computadoras de quinta generación.

La programación lógica consiste en la aplicación del corpus de conocimiento sobre lógica


para el diseño de lenguajes de programación; no debe confundirse con la disciplina de la
lógica computacional.

La programación lógica comprende dos paradigmas de programación: la programación


declarativa y la programación funcional. La programación declarativa gira en torno al
concepto de predicado, o relación entre elementos. La programación funcional se basa en el
concepto de función (que no es más que una evolución de los predicados), de corte más
matemático.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 5


Historia
Históricamente, los ordenadores se han programado utilizando lenguajes muy cercanos a las
peculiaridades de la propia máquina: operaciones aritméticas simples, instrucciones de
acceso a memoria, etc. Un programa escrito de esta manera puede ocultar totalmente su
propósito a la comprensión de un ser humano, incluso uno entrenado. Hoy día, estos
lenguajes pertenecientes al paradigma de la Programación imperativa han evolucionado de
manera que ya no son tan crípticos.

En cambio, la lógica matemática es la manera más sencilla,


para el intelecto humano, de expresar formalmente
problemas complejos y de resolverlos mediante la aplicación
de reglas, hipótesis y teoremas. De ahí que el concepto de
"programación lógica" resulte atractivo en diversos campos
donde la programación tradicional es un fracaso

Campos de aplicación

La programación lógica encuentra su hábitat natural en aplicaciones de inteligencia artificial


o relacionadas:

 Sistemas expertos, donde un sistema de información imita las recomendaciones de un


experto sobre algún dominio de conocimiento.
 Demostración automática de teoremas, donde un programa genera nuevos teoremas
sobre una teoría existente.
 Reconocimiento de lenguaje natural, donde un programa es capaz de comprender
(con limitaciones) la información contenida en una expresión lingüística humana.
 Etc.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 6


La programación lógica también se
utiliza en aplicaciones más
"mundanas" pero de manera muy
limitada, ya que la programación
tradicional es más adecuada a tareas
de propósito general.

Fundamentos
La mayoría de los lenguajes de programación lógica se basan en la teoría lógica de primer
orden, aunque también incorporan algunos comportamientos de orden superior. En este
sentido, destacan los lenguajes funcionales, ya que se basan en el cálculo lambda, que es la
única teoría lógica de orden superior que es demostradamente computable (hasta el
momento).

En qué consiste (ejemplo)


La programación lógica permite formalizar hechos del mundo real, por ejemplo:
las aves vuelan
los pingüinos no vuelan
"pichurri" es un ave
"sandokan" es un perro
"alegría" es un ave
y también reglas o restricciones:
Una mascota vuela si es un ave y no es un pingüino

Ante dicho "programa" es posible establecer hipótesis que no son más que preguntas o
incógnitas, por ejemplo:

¿ "pichurri" vuela ?

¿ qué mascotas vuelan ?....

Gracias a que la lógica de primer orden es computable, el ordenador será capaz de verificar
la hipótesis, es decir, responder a las incógnitas:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 7


Es cierto que "pichurri" vuela.

"pichurri" y "alegría" vuelan.

Obsérvese que el programa lógico no


solamente es capaz de responder si una
determinada hipótesis es verdadera o
falsa. También es capaz de determinar
qué valores de la incógnita hacen cierta la
hipótesis.

Este ejemplo es claramente académico. Sin embargo, consideremos el siguiente ejemplo: el


sistema de control de semáforos de una ciudad.

El estado de cada uno de los semáforos (verde, rojo o ámbar) constituye los hechos del mundo
real. El programa en sí consiste en unas pocas reglas de sentido común: determinados
semáforos no pueden permanecer simultáneamente en verde, un semáforo solamente puede
transitar de verde a ámbar y de ámbar a rojo, etc. La hipótesis es el estado en el que deberían
estar cada uno de los semáforos en el siguiente instante de tiempo.

Éste es un ejemplo imposible de resolver mediante programación tradicional, ya que la lógica


subyacente al comportamiento de los semáforos en su conjunto queda enmascarada por
simples órdenes imperativas del tipo "cambiar color de tal o cual semáforo".

El paradigma funcional
El objetivo del paradigma funcional es conseguir lenguajes expresivos y matemáticamente
elegantes, en los que no sea necesario bajar al nivel de la máquina para describir el proceso
llevado a cabo por el programa, y evitando el concepto de estado del cómputo. La secuencia
de computaciones llevadas a cabo por el programa se regiría única y exclusivamente por la
reescritura de definiciones más amplias a otras cada vez más concretas y definidas, usando
lo que se denominan definiciones dirigidas.

Todo esto con el objetivo de familiarizar a los estudiantes con un lenguaje elegante en el
cual se pueda manejar más fácilmente y así los programas sean menos extensos y complejos.

Otro de los objetivos primordiales de dicho paradigma es buscar satisfacer las necesidades
del usuario con respecto a operaciones matemáticas y convertirse en un lenguaje más
expresivo.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 8


Historia
Sus orígenes provienen del Cálculo Lambda (o λ-cálculo), una teoría matemática elaborada
por Alonso Church como apoyo a sus estudios sobre Computabilidad. Un lenguaje funcional
es, a grandes rasgos, un azúcar sintáctico del Cálculo Lambda.

Cálculo Lambda
Los orígenes teóricos del modelo funcional se remontan a la década del 30, mas precisamente
al año 1934, cuando Alonso Church introdujo un modelo matemático de computación
llamado lambda calculo.

A pesar de que en esta época las computadoras aun no existían el lambda cálculo se puede
considerar como el primer lenguaje funcional de la historia y sus fundamentos fueron la base
de toda la teoría de la programación funcional y de los lenguajes funcionales desarrollados
posteriormente. Se puede decir que los lenguajes funcionales modernos son versiones de
lambda cálculo con numerosas ayudas sintácticas.

Características
Los programas escritos en un lenguaje funcional están constituidos únicamente por
definiciones de funciones, entendiendo éstas no como subprogramas clásicos de un lenguaje
imperativo, sino como funciones puramente matemáticas, en las que se verifican ciertas
propiedades como la transparencia referencial (el significado de una expresión depende
únicamente del significado de sus sub expresiones), y por tanto, la carencia total de efectos
laterales.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 9


Otras características propias de estos lenguajes son la
no existencia de asignaciones de variables y la falta de
construcciones estructuradas como la secuencia o la
iteración (lo que obliga en la práctica a que todas las
repeticiones de instrucciones se lleven a cabo por
medio de funciones recursivas).

Existen dos grandes categorías de lenguajes funcionales: los funcionales puros y los híbridos.
La diferencia entre ambos estriba en que los lenguajes funcionales híbridos son menos
dogmáticos que los puros, al admitir conceptos tomados de los lenguajes procedimentales,
como las secuencias de instrucciones o la asignación de variables.

En contraste, los lenguajes funcionales puros tienen una mayor potencia expresiva,
conservando a la vez su transparencia referencial, algo que no se cumple siempre con un
lenguaje funcional híbrido.

Entre los lenguajes funcionales puros, cabe destacar a Haskell y Miranda. Los lenguajes
funcionales híbridos más conocidos son Lisp, Scheme, Ocaml y Standard ML (estos dos
últimos, descendientes del lenguaje ML).

La programación funcional, es un modelo basado en la evaluación de funciones matemáticas,


entendidas como mecanismos para aplicar ciertas operaciones sobre algunos valores o
argumentos, para obtener un resultado o valor de la función para tales argumentos.

Sin embargo, tanto argumentos como resultado de una función, pueden ser otra función, o
incluso la misma, tal como una forma de recursividad, que constituye una poderosa
herramienta de la programación funcional

Lenguajes Funcionales
Los matemáticos desde hace un buen tiempo están resolviendo problemas usando el concepto
de función. Una función convierte ciertos datos en resultados. Si supiéramos cómo evaluar
una función, usando la computadora, podríamos resolver automáticamente muchos
problemas.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 10


El lenguaje funcional más antiguo, y seguramente el más popular hasta la fecha, es LISP,
diseñado por McCarthy [1] en la segunda mitad de los años 50. Su área de aplicación es
principalmente la Inteligencia Artificial. En la década de los 80 hubo una nueva ola de interés
por los lenguajes funcionales, añadiendo la tipificación y algunos conceptos modernos de
modularización y polimorfismo, como es el caso del lenguaje ML.

Programar en un lenguaje funcional significa construir funciones a partir de las ya existentes.


Por lo tanto es importante conocer y comprender bien las funciones que conforman la base
del lenguaje, así como las que ya fueron definidas previamente. De esta manera se pueden ir
construyendo aplicaciones cada vez más complejas.

Scheme
Scheme es un lenguaje funcional, derivado de LISP. Scheme es un lenguaje compacto con
un alto grado de abstracción, por lo cual resulta adecuado para cursos introductorios de
computación, donde el énfasis está en la metodología de resolución de problemas. Scheme
permite resolver problemas complejos con programas cortos y elegantes. De este modo, el
lenguaje se convierte en un aliado para resolver problemas, no un problema más que resolver.

Los paradigmas lógicos, funcional y orientados a objetos interactúan en el desarrollo de


soluciones computarizadas, realizando software de alta calidad y productividad en todos los
campos de la ciencia y de la sociedad.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 11


El Paradigma Orientado a Objeto POO

Podemos afirmar, que es la tónica del momento,


este paradigma de la ciencia de la computación ha
logrado en pocos años, de los 80s a la fecha
mantenerse en la cima de las aplicaciones
tecnológicas de computación.

Como un proceso natural de desarrollo a partir de los principios de la programación


estructurada, continua la programación orientada a objeto como un complemento y mejora
sustancial de la estructurada, esto ha generado múltiples usos en el campo científico, por lo
que podemos afirmar, que el paradigma orientado a objeto es la medula espinal del desarrollo
del software en la actualidad.

Es gracias a la programación orientada a objeto que la computación abrió


sus puertas al acceso de todas las personas e instituciones, existen otras
razones que también ayudaron a lo mismo, este paradigma vino a simplificar
el manejo de programas, aunque no necesariamente el trabajo del
desarrollador de aplicaciones, el programa sufrió una verdadera revolución
en su concepción de elaboración, todo en beneficio del usuario final del
mismo.

La programación orientada a objeto fue la respuesta a la gran complejidad de las


organizaciones modernas, que requerían de mecanismos rápidos de adaptación y manejo de
las personas dentro de las empresas y de sus procesos de trabajos, sean estos productivos, de
servicios o de cualquier otra índole.

En principio podemos afirmar que la programación orientada a objeto es que un sistema de


software se observa como un conjunto de secuencia de transformaciones a lo largo de la
aplicación, permitiendo la adecuación constante de estas transformaciones a través de la vida
del software, permitiendo una vida más larga y una utilidad de mayor relevancia.

En lo referente a este curso, abarca un estudio sobre el paradigma de programación orientado


a objeto, su metodología de análisis y diseño en el paradigma en cuestión. También
estudiaremos un lenguaje de programación de uso muy popular en el mercado y de fácil
acceso para crear aplicaciones basadas en objetos y orientadas a objetos, este lenguaje es el
Visual Basic, creado por la empresa MICROSOFT; y al final haremos una breve introducción
a las bases de datos orientadas a objetos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 12


1.1.2.- Surgimiento y desarrollo del Paradigma Orientado a Objeto.
Dos desarrolladores de lenguaje a inicios de los años 60 del siglo XX , Krysteen Nygaaard
y Ole-Johan Dhal crearon el lenguaje SIMULA en el Norwegian Computer Center (NCC),
el uso de este lenguaje era para modelar simulaciones de procesos industriales y científicos
y de sistemas en general.

Al aplicar el lenguaje los usuarios observaron que se podía utilizar en otras situaciones
diferentes a las de simulación de sistemas y empezaron a implementarlo en áreas diferentes
a las propuestas originalmente; el lenguaje fue perfeccionándose en los años siguientes , y
en la versión de SIMULA- 67 toma el concepto de Objeto, esta idea de estructura era
utilizada por el lenguaje ALGOL-60 .

La principal características de los “objetos” de SIMULA-67 es que tenían vida


propia y se intercomunicaban entre si durante el desarrollo de los procesos, a las
operaciones se les llamaron métodos; y también se introdujo la noción de clases ,
que servía para describir la estructura y comportamiento de un conjunto de
objetos

Entre las principales características del lenguaje de SIMULA-67 podemos observar :

1.- Usa el concepto de encapsulamiento y objeto estructura donde se agrupan atributos de


datos y acciones (métodos y procedimiento) que procesan datos.
IMPORTANTE
2.- Clases utilizadas como plantillas o patrones de objetos

3.- Herencia acción de agrupar propiedades comunes en varias clases

4.-Polimorfismo: Clases con interfaces idénticas y propiedades que se puedan intercambiar

Estas características, que son propias del paradigma orientado a objeto las analizaremos con
más detalles posteriormente.

SIMULA -67 genera Smalltalk (1980), que se puede considerar como el primer lenguaje
propiamente orientado a objeto, su creador Alan Kay de Xerox Parc aplico todas las
características del paradigma y las implemento en su trabajo. A partir de entonces se han
desarrollado una gran cantidad de lenguajes orientados a objetos (LOO), algunos lenguaje
son :

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 13


Smalltalk -80
C ++
Actor
Objective- C
CLOS
Object Pascal
Object Cobol
Java
Eiffel

Lenguajes Visuales basados en objetos y orientados a objetos

Java es un nuevo lenguaje de propósito general, propio para escribir programas en


Internet, este lenguaje es totalmente orientado a Objeto y puede considerarse como una
excelente mejora de C++.

Podemos afirmar que el paradigma orientado a objeto reina en las metodologías actuales y
pasaran varios años para que resulte un nuevo paradigma para que la reemplace totalmente.
La programación orientada a objeto vino para quedarse y mejorar nuestras vidas.

OBJETOS

CLASES
CARACTERISTICAS ENCAPSULACION
DEL PARADIGMA
ORIENTADO A OBJETO POLIMORFISMO

HERENCIA

Java es un lenguaje moderno derivado de C y


C++, por lo que guarda y utiliza todas las
características de estos lenguajes de
programación, adicionándoles el uso de las
características del paradigma orientado a
objeto

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 14


1.2.- Objetos y Clases

1.2.1.- Objetos

Lo que hace al paradigma orientado a objeto muy interesante es la facilidad de reflejar


sucesos del mundo real mediante estructuras de objetos, podemos afirmar que el mundo real
está lleno de objetos, el televisor que utilizamos, el celular para comunicarnos, el semáforo
que controla el transito, la contraseña para ingresar al servicio del cajero automático, el
formato que llenamos en una aplicación, los seres humanos, la tierra , el Sistema Solar, la
galaxia ,todo está formado por objetos. Vivimos e interactuamos con objetos desde que
nacemos.

La principal característica de los objetos, desde el punto de vista de computación,


es que contiene información, es decir datos que los caracterizan de una forma
particular y también realizan acciones (procedimiento o funciones) para
interactuar con otros objetos.

Los ejemplos dados anteriormente, el televisor, celular, etc. Como sabemos comparten
características comunes, es decir por ejemplo todos los televisores se apagan, encienden
cambian de canal, nivelan el sonido…, ahora cada televisor podrá funcionar de manera
específica, los automóviles se trasladan aun con diferentes mecanismos de conducción
gasolina, diesel, gas, etc.

Cada objeto es una instancia de una clase, lo que lo ubica en dicho conjunto de objetos de
dicha clase, esta clase, como lo vimos anteriormente contiene datos y métodos que la
identifican plenamente del resto del mundo de los objetos.

Definición de objeto

Un objeto es una abstracción de cosas (entidades) del mundo real talque todas las
cosas del mundo real, llamadas instancias, tienen las mismas características y
además todas las instancias siguen las mismas reglas.

ATRIBUTOS

Partes de
Un objeto
OPERACIONES

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 15


Cada objeto consta de estados (atributos) y operaciones o comportamientos
(llamados métodos los cuales son invocados por mensaje)

Desde el punto de vista informático, los objetos son tipos abstractos de datos (tipos que
encapsulan datos y funciones que operan sobre esos datos)

Ahora surge la pregunta ¿Cómo podemos


identificar los objetos en el mundo real?, ¿Cómo
podemos deducir los objetos dentro del dominio
de la definición del problema?, después de una
intensa observación y descripción del problema
análisis gramatical del enunciado o descripción,
los objetos según Shlaer, Mellor y Coad/Yourdon
pueden caer dentro de las categorías:

Cosas tangibles (camión, bicicleta, batería, motor, libro)

Roles o papeles jugados o representados por personas (gerentes, operarios, usuarios cliente)

Organizaciones o instituciones (Empresas división, departamento, equipo)

Procesos u acciones que representan un suceso (evento) u ocurrencias, tales como llamada
a un servicio, juego, acción determinada, pueden ser física o real.

Interacciones Generalmente implican un contrato, o transacción y relacionan dos o más


objetos del problema en cuestión

Especificaciones muestran aplicaciones o plantillas de artículos, productos industriales

Lugares oficinas, sala de estudio, aula, muelle de embarque.

Cuando hemos determinados los posibles objetos pasamos a identificar los posibles
atributos y las operaciones sobre ellos

Los ATRIBUTOS describen la abstracción de características individuales que poseen


todos los objetos.

Ejemplos :

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 16


Objeto: Empleado :

Atributos: Nombre
Dirección
Ubicación
Nombre del departamento
Nivel de estudio

Objeto: Película

Atributos: Nombre
Director
Genero
Duración
Color

Objeto: Alumno

Atributos : Nombre Objeto: Alumno


Número de carné Juan Pérez
Ubicación 1678-4589
Carrera Ing. Computación
Fecha de ingreso 12/12/2011

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 17


Actividad de aprendizaje del alumno:

Realice un análisis de situaciones cosas u procesos que usted conozca y


represéntelos como objetos, al menos unos cinco, coméntelo con su grupo de
clase.

Las OPERACIONES O METODOS u


acciones cambian el comportamiento
del objeto referente a su
comportamiento original de alguna
forma, es decir pueden cambiar valores
de algunos de sus atributos, las
: operaciones podemos clasificarlas en
tres grupos

Operaciones o métodos que manipulan los datos de forma específica

Ejemplo Agregar, modificar, eliminar, Visualizar, Mover, Desplazar, etc.

Operaciones o métodos que realizan un cálculo o proceso específico ejemplo:


Calcular_distancia, mover, cerrar, Ejecutar_descuento,

Operaciones o métodos de comprobación (o monitoreo) un objeto frente a la ocurrencia


de un evento. Ejemplo: Verificar_edad, comprobar_id

También podemos preguntarnos ¿Cuánto dura un objeto? Los objetos son entidades por lo
que pueden ser creados o instanciados, por lo general a través de constructores como en
Java, Visual Basic, C++ o inicializadores

Veamos los ejemplos anteriores con algunas posibles operaciones


Objeto: Empleado :
Operaciones o Métodos:
Atributos: Nombre Agregar_empleado
Eliminar_empleado
Dirección
Calcular_salario
Ubicación
Calcular_deducciones
Nombre del departamento
Nivel de estudio

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 18


Objeto: Película

Atributos: Nombre Operaciones o Métodos:


Director Agregar_pelicula
Genero Eliminar_pelicula
Duración Modificar_pelicula
Color

Objeto: Alumno

Atributos : Nombre Operaciones o Métodos:


Número de carné Agregar_alumno
Ubicación Eliminar_alumno
Carrera Verificar_notas
Fecha de ingreso

Actividad de aprendizaje del alumno:

Realice un análisis de situaciones cosas u procesos que usted conozca y


represéntelos como objetos, al menos unos cinco, de forma completa sus
posibles atributos y operaciones, coméntelos con sus compañeros de clase

Comunicación entre objetos: Mensajes.

Un mensaje es una solicitud de un objeto a otro objeto al cual se le solicita


ejecutar uno de sus métodos, por convenio el objeto que envía la solicitud se le
llama emisor y el objeto que recibe la solicitud se denomina receptor.

Los mensajes pueden venir de:

a.- El exterior, ejemplo un ratón,


teclado, impresora.

b.- Otro objeto, el objeto A solicita


información al objeto B.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 19


Los objetos necesitan de los mensajes para interactuar con el exterior, es
su forma básica de comunicación

Aquí tenemos un ejemplo gráfico:

Objeto A
mensajes Objeto B

Datos Datos

Objeto C
Datos
Objeto D
Datos

Un mensaje consta de:

Identidad del receptor

El método que se debe ejecutar

Información especial necesaria a veces para realizar el método invocado

Cuando un objeto está inactivo – durmiendo - y recibe un mensaje se hace activo. El mensaje
enviado por otros objetos o fuentes tiene asociado un método que se activara cuando un
receptor recibe un mensaje.

1.2.- Clases
Otro elemento básico del paradigma orientado a objeto es el concepto de clases; La clase es
una estructura de lenguaje para definir tipos abstractos de datos en lenguajes de programación
orientados a objetos (POO), su aparición es desde 1967 en el lenguaje SIMULA y la define
como una entidad que declara conjuntos de objetos similares.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 20


Las clases son modelos o plantillas para objetos

|
Podemos afirmar que las clases son como los tipos ( ¿Qué es un tipo de dato? ) en un
lenguaje tradicional de programación con la salvedad que el usuario puede definir nuevos
tipos en un lenguaje orientado a objetos

Las clases son una descripción abstracta, ideal de un grupo de objetos,


cada uno de los cuales se diferencia por un estado especifico y es capaz
de realizar una serie de operaciones.

Gráficamente podemos representar una clase como un rectángulo.

Clase A

Ejemplo de clases:

1.- Madonna, Michael Jackson, Prince pertenecen a la clase “cantantes de rock”

2.- Los alumnos de segundo año de Ingeniería en computación de la UNI, pertenecen a la


clase “Estudiantes de Ingeniería en computación de segundo año de la UNI”

3.- Carlos Andrés Pérez, Violeta Barrios, Bill Clinton, pertenecen a la clase “Ex presidentes
de América”

Actividad de aprendizaje: Analice con su grupo de clase y asigne el nombre


posible de la clase de las descripciones siguientes, rellene los espacios

1.- Todos los clientes activos de un banco perteneces a una clase______________.

2.- Los perros pertenecen a la clase de los ____________ .

3.- Los vuelos de aerolíneas de la empresa XYZ pertenecen a una clase: ____________

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 21


4.- Los monitores de los computadores pertenecen a una clase._______________

5.- Los procesadores de los computadores pertenecen a una clase._________________

6.- Los alimentos que consumimos pertenecen a una clase._________________

7.- La tierra pertenece a la clase denominada “planetas”.

11.- Todos los automóviles pertenecen a la clase de ________________

12.- El proceso de matricula pertenece a una clase llamada _______________

Las clases deben contener datos, es decir, atributos que son propios de la clase y con los
cuales podemos realizar procedimientos (métodos) para obtener resultados esperados.

Los datos pueden ser de tipo público, los cuales interactúan con el mundo exterior y los datos
privados que son utilizados solamente por la clase, veamos algunos ejemplos de clase con
sus posibles propiedades y funciones o comportamiento:

Publico – interactúan con las otras clases


DATOS
Privado – interactúa solo dentro de la clase

Ejemplos de clases

Clases Posibles atributos Posibles comportamiento


Ser humano Piel Comer
Cabello Caminar
Extremidades Correr
Color de la piel Jugar
Automóvil Color Encender
Tipo de Chasis Apagar
Numero de puertas Correr
Número de Asientos Trasladar
Tipo de tablero Cargar

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 22


Otros ejemplos de clases:

Clase Posibles atributos Posible Comportamiento


Bicicleta Modelo Frenar
Velocidades Cambiar velocidades
color
Naranja Dulzura Pelar
Color Pudrirse
tipo Exprimir
Edificio Temperatura Abrir
Número de pisos Cerrar
Número de habitaciones Calefacción

Estudiante Nombre Cambiar clases


Dirección Matricular
Numero de Carne Graduar
Año de estudio Inscribir materias

Debemos tener en mente que lo que programamos son las clases y no los objetos, es
decir las abstracciones de datos, esta se realiza de diversas formas en los lenguajes
orientados a objetos.

Ejemplos de codificación de una clase en diversos lenguajes:

El lenguaje de programación Java tiene una forma para declarar una clase, analicemos el
siguiente ejemplo: (No se preocupe por la codificación, esta se analizara en detalle en una
unidad de estudio posterior)

Import java.io.*;

Class Primero {
Public static void.main (String args[] ) throws IOException
{
System.out.print (“Este es una aplicación en Java.\n”);
Sytem.out.print (“Esta es una clase llamada para realizar
impresiones.\n”);

} // Fin del main

} // Fin de la clase

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 23


Ejemplo de Clase en Visual Basic, Visual Basic tiene clases visuales tales como TextBox,
Label, form, etc y clases no visuales que pueden ser definidas por el usuario.

VISUALES – Formatos presentados por el lenguaje


CLASES EN
VISUAL
BASIC NO VISUALES- Elaborados por el programados según criterio
propio

Para definir una clase en Visual Basic este soporta su creación en la generación de modulo
de clases, esto permite la definición genérica de objetos, veamos el siguiente ejemplo:

Modelo de la definición en el modulo de clase de la clase CCliente

‘ Variables de miembro privado

Private m.nombre As sTring Declaración de datos privados


Private m.apellidos As String

‘Observemos que todos los procedimientos property son public de manera


‘ predeterminada

Property Get nombre() as string


‘ Devuelve el valor actual de la variable miembro
Nombre = m.nombre
Forma de escribir
End property
comentarios en Visual
Basic
Property Let Nombre (ByVal nuevoValor As string)
‘provoca error si se intenta una asignación de un valor no valido
If nuevoValor = “” then Err.Raise 5 ‘Procedimiento no valido
m.nombre = nuevoValor
End property
Forma de declarar
Function NombreCompleto() as string funciones en Visual Basic
NombreCompleto = Nombre & “ “ & Apellido
End Function

En C++ las clases se definen y se ejecutan, pero debe existir un procedimiento main() para
iniciar el programa y las llamadas de funciones , veamos el formato para definición de clase
en C++

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 24


// definición de clase (localizado en clasenombre.h )

class clasenombre
{
lista de variable miembro
lista de funciones miembro (usualmente prototipos o encabezados miembros
};

Nota : Observe el punto y coma después del cierre de llaves

Ejemplo especifico de clase en C++ :

// Clase luz
{
private:
int status // Luz esta en On(1) o en Off(0)
public:
luz() ; // constructor por defecto
luz ( int statusIn); // constructor para especificar estado
int cambio(); // Cambiar el estado
void printStatus(); // imprimir o visualizar le estado actual
};

Nota : // Sirve para presidir comentarios en C++ o Java

1.3 Encapsulamiento o Encapsulación


El concepto de Encapsulamiento es el siguiente, cuando tomamos el control remoto de un
televisor, este aparato podemos utilizarlo para muchas funciones y solo sabemos que
funciona!, ¿Cómo funciona ?, ¿Cómo guarda los datos que le programamos? No lo
sabemos pero obtenemos la respuesta que esperamos, el control remoto del televisor es
como una caja negra, no sabemos que contiene ni como ejecuta,. Solo sabemos el resultado.

El Encapsulamiento – a veces llamado también Ocultamiento de la información


es la idea de empacar juntas en una unidad de programación una colección de
miembros de datos y sus funciones (operaciones )bien definidas.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 25


Debemos saber que encapsulación es el significado de empacar datos y/o operaciones dentro
de una sola unidad (clase) de programación bien definida.

MUY
IMPORTANTE

Con el ocultamiento de la información logramos establecer una relación de vinculación entre


las operaciones y sus datos , la unidad – es decir la clase- , tiene una interfaz por medio del
acceso de sus datos miembros públicos , y la sección privada proporciona información que
se accesa solamente desde la clase, solo las operaciones miembros definidas en la clase
funcionan sobre los miembros de la clase privada, de esta forma , la sección privada de una
clase proporciona el ocultamiento de la información.

Sin Encapsulamiento ni ocultamiento de la información, no tenemos relación de vinculación,


esto no garantiza seguridad y que eventos ajenos a la clase puedan alterar el contenido y
proceso de la misma, además logra que las operaciones definidas sean las únicas que se
realizan en la clase, esto permite seguridad a la hora de realizar aplicaciones en el mundo
real.

En lenguajes que no tienen la propiedad de encapsulación los datos y las funciones que las
operan se determinan de manera separada, después se colocan juntas en un archivo de código
y se ejecutan, esta situación puede permitir algunas veces, irregularidades que conllevan a
resultados no deseados en el desarrollo de las aplicaciones

Como en el paradigma
estructurado…

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 26


CLASE Métodos Privados

Métodos públicos

Variables de instancias
privadas

El encapsulamiento presenta la seguridad, los métodos públicos protegen los


datos privados.

Actividad de aprendizaje Analice en grupo,


con sus compañeros, lea cuidadosamente los
dos enunciados que siguen y diseñe una clase
en cada caso.

a) Una clase cuadrado que consiste en la altura y el la longitud con funciones para
inicializar los miembros privados, calcular el perímetro del cuadrado y el área del
mismo.

¿Existe otra forma de diseño alterna a la propuesta?, justifique su respuesta

b) Una clase estado de cuenta de cliente que utiliza el monto depositado, la taza de
interés y el tiempo de ahorro, calcular el monto final a retornar cuando se venza el
período.

Con sus compañeros de grupo escriba por lo menos dos diseños alternos de la
clase

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 27


1.4 Herencia
Una característica muy importante del paradigma orientado a objeto además de los vistos
anteriormente es la de herencia.

La Herencia es la capacidad de permitir a los objetos ser construidos a partir de


otros objetos

La idea de herencia parte de la experiencia de la vida real las clases básicas o fundamentales
se dividen en subclases, por ejemplo los seres humanos se dividen en varones y mujeres,
los animales se dividen en mamíferos, insectos, peces, etc., la clase automóvil se puede
dividir en automóviles de lujo, de carrera, anfibios, de carga …

La herencia se utiliza con el fin de la


reutilización del código original utilizado en la
clase fundamental y variarlo en una subclase
especifica.

El principio de la división se basa en la jerarquía compartiendo características comunes, por


decir, todos los seres humanos, tienen extremidades, color de piel, respiramos, caminamos,
corremos.

La herencia es una jerarquía de clases (Superclases - Clases derivadas)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 28


La herencia parte de una clase fundamental llamada base o superclase y basado en la
jerarquía de clases derivamos unas subclases llamadas clases derivadas. las nuevas clases,
las clases derivadas, pueden heredar el código y los datos de su clase base , a esto le añadimos
su propio código especial y datos de ella, en la clase derivada podemos cambiar los datos
heredados para beneficio propia de la subclase.

Las clases mantienen relaciones con otras


clases, diferente a las relaciones con las
clases derivadas, las clases existentes en la
aplicación expresan las características
exactas de su clase y estas sirven como una
plantilla o modulo, entonces las clases
derivadas heredan características de la clase
base, y pueden agregar sus propias
características.

En muchos lenguajes una subclase también puede ser una superclase de otra clase, la clase
automotores puedes ser una superclase de la clase motocicleta, camión y auto, camión puede
ser superclase de las clases derivadas camión de combate y camión de carga, y así
sucesivamente.

Algunos lenguajes de programación permiten que una superclase o clase base sea una clase
abstracta con métodos posiblemente indefinidos, entonces cada subclase puede definir el
método como se requiera. (Esto se conoce como polimorfismo, que lo estudiaremos mas
adelante)

Una clase abstracta sirve como una sección de métodos y atributos compartidos para las
subclases del nivel inmediatamente inferior. Estas no tienen instancias directamente y su
función principal es agrupar otras clases y capturar información que es común al grupo, la
clase abstracta es un ”contenedor”, las subclases de clases abstractas que corresponden a
objetos del mundo real pueden tener instancias.

Una clase abstracta es una clase que sirve de base común, pero esta no tendrá instancias

Podemos identificar dos tipos de herencias en las clases, herencia simple y herencia múltiple

En la herencia simple o herencia jerárquica, una clase u objeto hereda solo una subclase, es
decir una subclase puede heredar datos y métodos de una única clase base, también puede
modificar – agregar o quitar – comportamientos de la clase base, algunos lenguajes de
programación orientado a objetos solo permiten este tipo de herencia.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 29


En la herencia múltiple o herencia de malla, una subclase puede tener mas de un ascendiente
inmediato, es decir, puede heredar de mas de un clase base (súper clase), esta herencia
puede ser reemplazada por medio de la herencia simple y a veces es mejor utilizar este tipo
de herencia, C++ permite la herencia múltiple, Smalltalk, no permite la herencia múltiple
pero Eiffel si.

Podemos afirmar que por lo general todo lo que hacemos con la herencia múltiple se puede
realizar con la herencia simple.

Clase cliente de Banco

Cuenta de ahorro Cuenta de cheques

Cuenta en córdobas Cuenta en dólares

La clase cliente de Banco es la clase base o superclase, la cual deriva en las clases cuenta
de ahorro y de cheques (Clases derivadas) y estas a la vez son superclases de otras

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 30


1.5 Polimorfismo
Esta propiedad de la programación orientada a objeto , en su esencia es, el uso de un nombre
o símbolo para representar o significar mas de una acción o método, por ejemplo los
operadores aritméticos son un clásico ejemplo de esta característica , el operador + se utiliza
para sumar valores numéricos, pero también se utiliza para concatenar cadenas de caracteres
.

Se denomina polimorfismo (del griego polymorphos = muchas formas), cuando un operador


existente en el lenguaje tales como +, = ,*, tienen la posibilidad de operar sobre diversos tipos
de datos ( enteros , dobles, caracteres) , entonces decimos que esta sobrecargado.

La ventaja del uso del polimorfismo y la sobrecarga de los operadores o métodos de las
clases, es que permite que los nuevos tipos de datos sean manipulados de manera similar.

Podemos afirmar que el polimorfismo supone que un mismo mensaje puede


producir acciones o resultados totalmente diferentes cuando estos actúan sobre
objetos diferentes.

El polimorfismo se lleva a cabo usando funciones virtuales o funciones sobrecargadas,


estas funciones tienen características muy propias para su elaboración.
Las funciones sobrecargadas se llaman usando enlace estático

Las funciones virtuales se llaman usando enlaces dinámicos.

Un enlace se refiere al tiempo real cuando se anexa o se une el código a una función dada.

1.6 Sobrecarga de Operadores y Funciones

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 31


La sobrecarga es la capacidad de utilizar el mismo nombre de operación para funciones
similares que tienen un comportamiento diferente cuando se aplicas a clases diferentes. Esto
lleva por consiguiente que los nombres de las operaciones se puedan sobrecargar .

Si los nombres de una operación se utilizan para nuevas definiciones en clases de una
jerarquía, la operación a nivel inferior anula la operación a nivel superior. Analicemos el
siguiente ejemplo de una sobrecarga en las clases y sus derivadas.

La sobrecarga se presenta cuando los métodos tienen el mismo nombre, pero se


aplica a datos distintos, lo que sucede entonces es que el compilador puede
determinar que operador utilizar en tiempo de compilación y así manejar la
función correcta.

Analicemos un ejemplo de sobrecarga:

En Java por ejemplo únicamente presenta un sobrecarga en el operador + con cadenas de


caracteres y otros tipos de datos primitivos (int, double…), por lo que podemos utilizar
operaciones del tipo:

Int x = 12;
“Valor de x es: “ + x;

Cuando el compilador Java se encuentra con esa operación no realiza suma aritmética sino
que convierte el valor entero 12 en la cadena “12” y concatena o une con la cadena operando
de la izquierda.

En trabajo colaborativo con sus compañeros realice los siguientes ejercicios y designen un
secretario relator para que explique cualquiera de los ejercicios delante de toda la clase de
acuerdo a lo orientado por el profesor.

La sobrecarga de operaciones no es propia solo de


los lenguajes orientados a objetos, el lenguaje C,
Pascal y otros del paradigma estructurado
soportan la sobrecarga de operaciones, la
sobrecarga se aplica solamente a las operaciones,
pero, puede extenderse esta propiedad a los
atributos y relaciones específicas del modelo de
estudio

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 32


Resumen del Capitulo

En Conclusion:

El paradigma orientado a objeto es de


amplia utilización en el desarrollo de
aplicaciones de computación y otras
tecnologías, desarrollado desde los años
60 del siglo XX, toma su máximo
desarrollo a partir de los años 80’s con la
aparición de Smalltalk y otros paquetes
con características orientadas a objeto.

El paradigma orientado a objeto tiene sus propias características que lo definen como tal entre
las principales tenemos:

Objeto es algo real que se puede manejar


en un programa, el objeto lo debemos
definir por una clase determinada para
poder usar esta. Los objetos son
instancias de la clase que lo define

Clase es una interfaz modelo o plantilla que define el comportamiento de un conjunto de


objetos que presentan características similares tanto en la definición de sus datos miembros
como de sus posibles comportamientos (métodos o funciones de la clase)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 33


Encapsulación Es la
capacidad de trabajar con los
datos y métodos (o
procedimientos)
considerándolo como una
unidad, el Encapsulamiento
permite a las funciones de la
clase trabajar solo con los datos
privados de ellas, evitando el
ingreso de datos intrusos
externos a la clase, esta
característica ofrece robustez a
la programación orientada a
objeto.

Polimorfismo es la propiedad que


permite el uso del mismo método o
función trabajar con valores de datos
distintos, el compilador se encarga de
asignar la operación correspondiente
correcta.

Herencia es la propiedad de la programación orientada a objeto que permite a una clase


llamada base o superclase heredar datos y métodos a otras llamadas derivadas o subclases,
esto permite reutilizar el código creado en la creación de las mismas varias veces

Mensajes los objetos forman parte de un conjunto complejo de acciones y eventos que se
presentan a lo largo de un problema de la vida real, con la interacción de los objetos, lo que
se logra a través de mensajes, los programadores consiguen una funcionalidad de alto nivel
y un comportamiento más complejo.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 34


Ejercicios de reforzamiento de la unidad

En trabajo colaborativo con sus


compañeros realice los siguientes
ejercicios y designen un secretario
relator para que explique
cualquiera de los ejercicios delante
de toda la clase de acuerdo a lo
orientado por el profesor.

1.- Describa y justifique los objetos que obtiene de cada uno de los enunciados:

1.1.- Los habitantes de Managua y sus direcciones de habitación


1.2.- los clientes de un banco, con préstamos hipotecarios
1.3.- los alumnos de primer ingreso de una universidad
1.4.- Los empleados de una empresa y su puesto de trabajo
1.5.- Las presentaciones de películas en salas de cine.

2.- Defina los objetos en los siguientes sistemas:

2.1.- Un celular
2.2.- Un sistema de registro de estudiantes
2.3.- Un sistema de suscripción a una revista
2.4.- Un sistema de control de mercadería en una tienda
2.5.- Un control de clases recibidas en un semestre

3.- Realice un trabajo de auto estudio y análisis con su grupo de clase sobre lo siguiente:

3.1.- ¿Qué diferencia existe entre un objeto y una clase?, Investigue que es una instanciación
y explíquelo con un ejemplo

3.2.- Explique el polimorfismo de manera grafica con un ejemplo específico, ¿Cuál es su


ventaja, que optimiza?

3.3.- ¿Cuáles son las ventajas de la encapsulación en los objetos? Realice un cuadro de esas
ventajas

3.4.- ¿Cuáles son las dos secciones principales que forman la estructura de una clase?

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 35


4.- Realice los siguientes trabajos y exprese su opinión sobre ello en clase expositiva

4.1.- ¿Cómo implementamos la herencia en un lenguaje como java?, escriba un ejemplo y


explíquelo brevemente.

4.2.- Algunos lenguajes de programación orientados a objetos utilizan los eventos, en qué
consisten? De un ejemplo especifico en VISUAL BASIC y preséntelo en la clase de
presentación

4.3.- Una ventana de un programa de computadora se puede considerar como un objeto de


una clase ventana, ¿Qué datos y operaciones deben ser parte de este objeto? ¿Por qué razón,
explique?

4.4.- ¿Una clase es una interfaz Si o No, por qué? Investigar y presentar sus anotaciones
resumidas en un documento.

5.- Definir una clase EMPLEADO que represente a los empleados de una empresa, si
tenemos la información disponible para cada empleado que es:

Nombre del empleado


Puesto de trabajo
Salario bruto por hora
Estos tienen entre otras responsabilidades:
Inicializar un nombre de empleado a blanco
Designar salario bruto a 0.00
Determinar el salario

¿Cuál información dada puede ser atributo? Cuáles pueden ser operaciones, diseñe un
algoritmo para la operación determinar salario, explique porque considera correcta esa
operación algorítmica?

6.- Escriba una clase de nombre CALENDARIO que conste de unos ochos o más
campos de atributos y que contengan la fecha y por los métodos u operaciones tenemos:

a) Construir una fecha dados el día, mes y año


b) Determinar si la fecha es valida
c) Retornar la siguiente fecha a una fecha determinada
d) Devolver el nombre del día de la semana correspondiente a una fecha dada
e) Devolver el nombre del mes correspondiente a una fecha dada.

Realice un algoritmo por cada método u operación dada en el ejercicio. Prepare la respuesta
y preséntela con sus compañeros

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 36


II UNIDAD
Sistemas de información
El analista en su desempeño realiza diferentes tipos de sistemas de información,
todo con el objetivo de satisfacer las demandas y/o necesidades de cada nivel de
una institución o empresa en la cual realiza su trabajo.

¿Qué es un
analista de
sistema?

En las instituciones se presentan muchos sistemas de información, pero podemos


nombrar las categorías que mas se presentan:

Sistemas de carácter transaccional:


Estos sistemas procesan grandes cantidades de información, que se utilizan como
insumo para generar una gran cantidad de información valiosa para los ejecutivos y
responsables de la toma de decisiones en los niveles superiores.

Podemos decir que una transacción representa un evento o situación que se


realiza muchas veces en la empresa , por ejemplo revisar el saldo de los clientes,
los pagos realizados por los mismos, los pedidos que solicitan los clientes, etc,.

Entre las transacciones más comunes podemos encontrar los sistemas de:

Pedido de mercaderías
Compra de artículos insumos en la empresa
Facturación a clientes
Pago de nomina a empleados
Deposito de cheques u otras transacciones en el banco.

La principal característica de los sistemas transaccionales incluye actividades


repetitivas de cálculos de operaciones, organización y clasificación de la
información, almacenamiento de una forma segura y de fácil acceso a las
personas autorizadas para ello.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 37


Estos procedimientos facilitan la mecánica de cada transacción, su secuencia en la
realización y los pasos a dar cuando existan excepciones de las mismas. Estos
sistemas so de carácter operativo y existen en todas las empresas, además son los
primeros en ser automatizados, pues como lo manifestamos anteriormente sirve de
insumo para sistemas de mayor jerarquía, por otro lado dicha automatización
permite mejorar las actividades rutinarias de la empresa.

Los sistemas transaccionales permiten el almacenamiento de la información en las


bases de datos de las empresas, para un mejor manejo y utilización de los mismos.

Actividad de reforzamiento de estudio


Pregunta de análisis para el grupo de trabajo

1.-¿Todas las instituciones tienen sistemas transaccionales? Justifique su


respuesta

2.- ¿Cual es la principal característica de los sistemas transaccionales?

Sistemas de información gerencial:

También conocidos como sistemas de información administrativa, ya que permite


ayudar a los administradores en la toma de decisiones de manera científica y
estructurada, lo que permite resolver los problemas a nivel intermedio de la
empresa.

Estos sistemas permiten organizar, estructurar y filtrar los datos de los


sistemas transaccionales para la emisión de reportes en forma periódica a las
autoridades competentes, los cuales tomaran las medidas pertinentes para
optimizar la situación.

Estos reporte, a manera de ejemplo, podrían ser :

Reporte de pagos de clientes por sucursal


Reporte de ventas de X productos, por sucursal, por fecha.
Reporte de saldos de clientes
Reporte de porcentajes ganados por vendedor en cada sucursal
Reporte de impuesto a pagar en el mes.

Esta información el gerente podrá observar el comportamiento de la unidad y tomar


las acciones que considere conveniente para su mejora. Es decir que política tomar
con respecto al producto X de acuerdo al informe presentado sobre el mismo.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 38


Estos sistemas suelen ser realizados después de la implantación de los
sistemas transaccionales, estos depuran, filtran y organizan datos de acuerdo a
las necesidades de los ejecutivos de los datos de los sistemas transaccionales.

Relación entre tipos de


sistemas

Estos sistemas ofrecen una gran variedad de reportes y sirven de apoyo a la toma
de decisiones a nivel intermedio de la organización, además facilitan el trabajo al
tomar decisiones sobre datos reales actualizados en el sistema.

Cada área necesita un sistema gerencial especifico acorde a las necesidades


propias de dicha sección y en busca de obtener resultados rápidos y
correctos.
(Inventario, Finanzas, Recursos Humanos, Producción, etc.)

Actividades de reforzamiento de estudio

Con su grupo de estudio analice las posibles ventajas del uso de los sistemas
de información gerencial en contraste con las desventajas de no usarlos en
una empresa o institución.

Sistemas de soporte a las decisiones:


La principal características de estos sistemas es que sirven de apoyo a la toma de
decisiones de los niveles intermedios y altos de la organización. Estos sistemas
son intensivos en cálculos y escasos en entradas y salidas de información.

La principal características de ellos es de ser interactivos y muy amigables,


de una manera muy gráficos y/o visuales, suelen estar dirigidos a los usuarios
finales, en muchas ocasiones suelen ser desarrollados directamente con la
participación del usuario

Sistemas estratégicos:

Las empresas realizan uso de estos sistemas para obtener ventajas competitivas
con otras empresas del mismo tipo en el mercado, Su principal funciones lograr
ventajas que los competidores no los posean, sirven para apoyar situaciones de
la empresa tales como:

Mejora de productos y servicios que oferta la empresa.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 39


Reducción de costos por medio de alternativas viables de realización de los mismos
Innovación de productos y procesos.

Sistemas expertos:

Llamados también sistemas basados en el conocimiento, la inteligencia artificial es


el campo principal de los sistemas expertos.

Estos sistemas mejoran la calidad y eficiencia en los procesos de las tomas


de decisiones porque tienen muy poca dependencia de las personas, estos
sistemas permiten deducir por medios lógicos y heurísticos cual es la mejor
estrategia o solución a determinados problemas de tipo especifico planteado al
sistema.

Actividades de reforzamiento de estudio

Con su grupo de estudio analice las posibles ventajas del uso de los sistemas
de descritos arriba en contraste con las desventajas de no usarlos en una
empresa o institución. Exprese su opinión en un cuadro comparativo de
ventajas y desventajas de cada sistema de información.

INTRODUCCION AL ANALISIS Y DISEÑO DE SISTEMAS

Conceptos de Análisis y Diseño Estructurado.


Diseño de arriba – abajo:
Existen varias formas de buscar la solución a un problema desde el punto de vista
computacional, una de las formas mas usadas es por medio del paradigma
estructurado, el cual consiste en descomponer un problema en sus unidades
componentes y después analizar dichas unidades, si es necesario, que una unidad
se descomponga en nuevos componentes, pues lo hacemos y analizamos los
nuevos, y así sucesivamente.

El diseño de arriba –abajo proporciona este método para descomponer un


problema dado en sus unidades componentes o módulos. Este diseño recibe otros
nombres tales como diseño estructurado, diseño compuesto, etc. Todas estas
metodologías describen la descomposición del problema en sus funciones más
importantes, la subdivisión de esas funciones en subdivisiones y así
sucesivamente

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 40


Al aplicar este método, nos permite registrar los niveles de complejidad asociados
con cada solución, y además descubrir los requerimientos operacionales de los
procesos en cada sub unidad.

Cuando realizamos este tipo de análisis, el análisis estructurado, logramos evitar


soluciones ilógicas y soluciones relacionadas con solo una parte del problema
planteado. El dominio que aplica la solución se llama abajo –arriba. Porque este
método permite analizar un nivel a la vez con toda rigurosidad, permitiendo asegurar
todas las operaciones necesarias para satisfacer la solución.

Este método se puede visualizar por medio de graficas, llamadas diagramas de


estructuras, los cuales son parecidos a los organigramas de las empresas, con la
diferencia que estos presentan módulos en que han sido divididos. Estos módulos
mantienen algunas reglas muy importantes que se deben de cumplir:

1.- Cada modulo debe ser independiente de los demás módulos.


2.- La responsabilidad operacional de cada modulo debe
ser definida concisamente.
3.- Cada modulo debe ofrecer solo un punto de entrada.

Estas reglas permiten mantener una uniformidad en cuanto al flujo de los procesos
y de permitir navegar por el diagrama de estructura solamente por las relaciones
establecidas en cada modulo, además permite tratar cada uno de ellos como una
entidad independiente, logrando atacar sus necesidades hasta solventarlas.

El método arriba – abajo dominó los análisis de problemas informáticos hasta


los años 80`s, cuando la metodología orientada a objetos se desarrollo como
una alternativa nueva para solucionar problemas que la metodología
estructurada no lo hacia.

Ejemplo de diagrama de estructura:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 41


Proceso de nomina
de empleados

Leer datos de Procesar Emitir


empleados Pagos Reporte

Actividades de reforzamiento de estudio

1.- Realice un esquema resumen de media página con sus propias palabras
sobre el diseño estructurado

2.- ¿Por qué el diseño estructurado fue el primero en utilizarse en la ciencia


de la computación, explique sus razones?

3.- ¿Quiénes y en que periodo de tiempo se utilizo el diseño estructurado?¿


Se sigue utilizando?, Justifique su repuesta.

4.- Realice con sus compañeros de clases un debate sobre la importancia


actual del diseño estructurado.

5.- investigue y exponga en clase un modelo de sistema de información que


utilice el diseño estructurado.

Conceptos básicos de Análisis y Diseño Orientado a


Objeto (ADOO)
El análisis orientado a objeto es parte del paradigma orientado a objeto donde se
trata de resolver problemas en computación aplicando la metodología Orientada a
Objeto, esta metodología analiza la situación pensando en los procesos en algo
similar a la organización de un grupo de individuos, como un equipo, club o

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 42


asociación, puesto que cuando ocurre un evento en el equipo, este lo realiza un
miembro del grupo, el cual se responsabiliza de dicha acción. No existen acciones
–eventos- de por si, alguien o algo debe de responsabilizarse de ello.

El análisis orientado a objetos se basa en la solución del problema a partir


de objetos, es decir que la implementación del software será a partir de
comportamiento específicos de los objetos. Además los objetos tienen
procesos dinámicos en el análisis, estos pueden generar nuevos objetos,
crear nuevas relaciones entre los objetos, ser destruidos.

Es como analizar una estructura compleja , que se va armando por partes ,


sub partes, sub sub partes, etc.

En este tipo de análisis nos preocupamos por las acciones, llamadas eventos que
ocurren al interactuar los agentes (Objetos), cuanto mas definimos los posibles
eventos, cuando mejor los relacionamos en función de dar una solución real, en
tiempo, segura y completa del problema , el software será la solución al problema
lo mas ajustada a la realidad del mismo.

El análisis de los sistemas en el paradigma orientado a objetos, se realiza al definir


los objetos que actúan en el sistema, así como los eventos que interactúan
con ellos. La creación y manipulación de los objetos permite la reutilización del
software , y en caso necesario, construir nuevas clases , cuando modelamos el
problema de la empresa o institución los analistas deben identificar los tipos de
objetos y las operaciones necesarias para que los objetos se comporten de
determinada manera.

En el análisis orientado a objeto, la acción se inicia mediante la transmisión de


un mensaje a un agente, un objeto, responsable de la acción, este mensaje
tiene la petición de una acción y se acompaña de cualquier información, argumento,
que ayude para llevar a cabo esta solicitud. El receptor (otro objeto) es el agente al
cual se le envié el mensaje, si el objeto que atiende el mensaje, acepta la
responsabilidad de llevar a cabo una acción indicada en respuesta al mensaje, este
objeto ejecutara algún método para satisfacer la solicitud.

Volveremos sobre el análisis orientado a objetos en breve, pasaremos a estudiar un


poco sobre los sistemas de información que se presentan en las instituciones y
empresas del mundo real, el ingeniero de computación debe mantener una visión y
estrategia firme de las características que se presentan en los distintos entornos
donde se desarrollara.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 43


Ejemplo de diagrama de flujo de objetos:

Diseño de equipo para clientes de la empresa XYZ S.A.

Adquirir materiales Materiales de clientes


de construcción producción

Producir tarjetas de Tarjetas de Ensamblar Ensamblar


circuitos impresos circuitos computadora computadora
impresos s

Diseño de
Producir hardware
diseño

Actividades de reforzamiento de estudio


1.- ¿Cuál es la base de un análisis de sistema orientado a objeto?, explique
brevemente.

2.- Explique al menos tres eventos que se pueden presentar en un análisis de


sistema orientado a objeto de un proceso de matrícula de estudiante.
Justifique.

3.- ¿Qué interactúan en un análisis orientado a objetos, a través de que lo


hacen?

ANALISIS ORIENTADO A OBJETOS (AOO)


Debemos mantener presente que el análisis de los sistemas no cambia, aunque
cambien las herramientas de programación lo que cambia es el modelo que
enfoca dicho análisis.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 44


Así sabemos que en un análisis de sistema en el entorno de un problema enfocado
en dirección de un análisis estructurado, el analista, o los analistas utilizan un
Diagrama de Flujo de Datos (DFD) para construir su modelo. Cuando utilizamos el
análisis orientado a objetos utilizamos otras herramientas para llevar adelante el
modelo del sistema, utilizamos objetos, relaciones entre ellos y no solo datos.

Capas del Análisis orientado a Objetos (AOO):


Coad Yourdon aplica las siguientes capas como herramientas en el modelaje
orientado a objetos, estas cinco capas son:

1.- Capa de Clase y Objeto Esta capa identifica los objetos que interactúan en el
sistema, estos pueden ser cosas reales : papeles, eventos, transacciones o
especificaciones, como siguiente paso es identificar las clases y representarlas,
además podemos definir clases abstractas , es decir clase que no tengan ningún
objeto o instancia, pero no al contrario, es decir todo objeto debe tener una clase
que lo represente.

2.- Capa de estructura Esta capa indica las relaciones y las posibles herencias
entre las clases y objetos del sistema

3.- Capa de atributos Esta capa define los atributos de cada objeto para poder
manejarlos eficientemente dentro del sistema de estudio

4.- Capa de Servicios Esta capa no indica los mensajes y comportamiento del
objeto

5.- Capas de Tema Esta capa divide al modelo del sistema en unidades para facilitar
su estudio e implementación de los mismos.

Metodologías de Análisis y Diseño Orientados a


Objetos
El Paradigma orientado a Objetos busca el modelaje del mundo real y plasmarlo en
aplicaciones computacionales, este paradigma presenta, gracias a sus
características de encapsulación, herencia, polimorfismo, entre otras, herramientas
muy poderosas para la creación de aplicaciones.

En este segmento estudiaremos una breve introducción al modelado de objetos y


sus relaciones fundamentales, aplicaremos el concepto de herencia en las
relaciones de clases y su gran facilidad para reflejar situaciones que se presentan
en el mundo real.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 45


Si pensamos construir un sistema orientado a objeto, el primer paso es definir la
creación de clases (objetos) que representan el problema a resolver. La forma en
que se relacionan las clases y su funcionamiento interno de los atributos y métodos,
de las formas de comunicación mediante los mensajes, la forma de definirlas las
clases si se requieren abstractas o no, en que tipo de eventos actúan.

Como objetivo fundamental de un análisis del problema orientado a objeto (AOO)


es la definición de todas las clases que son relevante para el mismo, sus atributos
y operaciones, las relaciones y demás elementos que determinan el ámbito del
problema..

Analizaremos los tipos de relaciones que se pueden presentar en las clases


resultantes de un análisis con este tipo de enfoque

2.1. Relaciones de Clases


Cuando modelamos objetos, las clases al igual que los objetos tienen diferentes
formas de relacionarse entre ellas, con el propósito de lograr los objetivos
propuestos de la aplicación de estudio.

Según Booch existen en las relaciones de clases las siguientes formas:

Generalización/Especialización (es un)


Agregación (Todo-parte/Tiene un)
Asociación
Uso
Instanciación (Plantilla)
Metaclase

Abordemos un poco sobre ellas


2.1.1.- Generalización/Especialización (es un / is –a)
Un forma eficiente de organizar las clases es por medio de estructuras jerárquicas,
la herencia es un relación entre clases, donde sabemos, que comparten atributos
y/o métodos definidos en una (herencia simple) o mas clases (herencia múltiple).
Sabemos que se denomina superclase a la clase base que hereda una o mas
clases denominadas subclases.

Una subclase heredara atributos y comportamientos de una superclase de orden


jerárquico mayor. Gráficamente podemos verlo así:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 46


computador

desktop laptop

Teclado monitor

Grafico Subclases de la clase computador.

Jerarquías de generalización/especialización:
Cuando trabajamos con clases en el modelo, las reunimos con características
comunes en una clase especial llamada superclase, una superclase representa un
generalización de las subclases, de manera inversa una subclase representa una
especialización de una superclase.

Una manera importante en el análisis de un modelado de objetos es definir clases


que son muy generales y partir de ellas empezamos a especializar las clases
(subclases) que si tienen acción en el campo de definición del problema. A estas
clases que no existen les llámanos clases abstractas y su propiedad
fundamental es que no pueden crear instancias de ellas. Podemos afirmar por lo
tanto que la generalización es una abstracción de un conjunto de objetos de
propiedades similares representadas mediante un objeto genérico.

factura

credito contado

especial normal

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 47


Ejemplo de relación generalización de la clase abstracta factura

Cuenta cliente

Cuenta corriente prestamos Depositos

Generalización metodología OMT.


La relación de generalización se representa por un triángulo en la metodología OMT.

2.1.2 Agregación (Todo-parte/Tiene un)


Una agregación es una relación que representa a los objetos compuestos, es decir
un objeto que se compone a su vez de otros objetos , podemos tener como ejemplo
una persona se compones de sistemas biológicos: Óseo, muscular, endocrinico,
etc.. un edificio se compone de puertas, piso , ventabas, paredes, que a su vez son
también objetos

Cuando realizamos un análisis del mundo real, el problema se presenta de una


forma compleja, es decir, modelo compuesto de muchos objetos, que también
representan modelos a integrar a la solución, la agregación es un concepto que se
utiliza para expresar tipos de relaciones entre objetos parte-de (part-of) o tiene-
un (has-a), el nuevo objeto resultante es un objeto que se forma de múltiples
objetos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 48


automovil

PUERTAS RUEDAS LUCES

NEUMATICOS RADIO

Nota : Ejemplo de agregación (metodología OMT)

2.1.3 Asociación
Una Asociación es una conexión entre clases, es decir un enlace que define los
papeles o roles que juegan los objetos entre si, establecen su dependencia entre
los objetos de dos clases y su cardinalidad (multiciplidad), es decir cuántas
instancias de cada clase pueden estar aplicadas en una asociación.

Una asociación representa una dependencia bidireccional, a menos que se explique


una única dirección.

Por ejemplo una sala de cine exhibe una película y una película es exhibida en una
sala de cine, el objeto película se relaciona con el objeto sala de cine por medio de
la relación exhibe.

CINE PELICULA

Una relación de asociación se describe con frases tales como “ es miembro de “


“tiene un “, “ trabaja para “, etc.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 49


posee

persona vehiculo
1 0..n

Notación Grafica en la metodología Booch’93 podemos afirmar que una persona


puede tener 0 o mas vehículos, el carácter ● indica el origen de la relación tiene-un
Las opciones de cardinalidad en una relación tiene-un están :

1 exactamente 1
N Número ilimitado
0..N Cero o mas
1..N Uno o mas
3..8 Rango especifico
1..4, 7 Rango especificado o numero exacto

UML (Unified Modeling Lenguaje )


UML podemos considerarlo como lo mas representativo de los métodos de análisis
y diseño orientados a objetos que aparecieron a finales de los ochenta y primeros
años de los noventa, expertos tales como Coad/Yourdon, Shlaer y Mellor, Booch,
OMT, Jacobson. Han realizado grandes aportes al análisis del modelado de datos.

El UML define una notación y un metamodelo, la notación es la parte medular que


se presenta en los modelos, es la sintaxis del lenguaje de modelado, un metamodelo
es un modelo que representa al método orientado a objetos y lo define con rigor ,
es por lo general un diagrama de clases que define la notación.

Cuando realizamos un modelado orientado a objetos, las clases y los objetos con
sus respectivas relaciones son la parte fundamental del modelado. El modelo de
clase y objetos nos muestra el sistema que tratamos de describir. Cuando logramos
el modelo del sistema el siguiente paso es programar orientado a objetos, el análisis
orientado a objetos trata de crear modelos de dominios de interés de la aplicación,
es decir, que se pueda representar por medio de programas orientados a objetos.

Diagramas de clases:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 50


Un diagrama de clases es un tipo de modelo estático, podemos afirmar que un
modelo de diagrama de clases presenta una forma estática de un sistema en
términos de clases y sus relaciones

Persona
Atributos
Nombre relevantes Persona
Dirección
Edad
Notación reducida
Leer() Operaciones
Establecer_limite() Funciones
. Metodos
.

Notación de una clase

En un análisis orientado a objetos la creación de clases es un proceso altamente


creativo, fundamentalmente debemos tener un completo conocimiento del dominio
del problema.

Ejemplo de AOO: Utilización de tarjetas CRC

Fichas o tarjetas CRC (clase, responsabilidad, colaborador)


El uso de fichas para representar las clases individuales es una técnica, de las
muchas que existen, que se utiliza para asignar responsabilidades a cada acción,
esta fichas se conocen como Tarjetas CRC (Beck 89) , una tarjeta CRC esta
dividida en tres partes

Clase : Nombre en la esquina superior izquierda que es de la clase que esta


definida, la selección de nombres de clases es de suma importancia , puesto que
con los nombres de las clases se crea el vocabulario con el que se formulara
el diseño.

Responsabilidades : Están descritas debajo del nombre de la clase, estas


describen el problema que se va a resolver , estas frases deben ser cortas, que
expresen un verbo activo, deben describir que se debe hacer y evitar los detalles
de cómo se deben hacer.

Colaboradores: Los objetos necesitan de la colaboración de otros objetos,


cuando solicitan una acción por medio de mensajes, casi todos los objetos guardan
relación con otro objeto del sistema. La clase colaboradora se escribe en la parte
derecha de la ficha CRC.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 51


Ejemplo de tarjeta o ficha CRC:

Modelo de un cajero automático

VerificadorDeDatos Colaboradores

Muestre mensaje de bienvenida, espere VerificadorNIP


tarjeta
VerificadorDeActividad
Pida al VerificadorNIP que compruebe
datos

Llame al SelectorDeActividad

Devuelva Tarjeta al usuario

La clase VerificadorDeDatos tiene cuatro responsabilidades que se detallan en la


tarjeta y dos clases colaboradoras que se relacionan con ella para satisfacer sus
responsabilidades, la creación de clase por medio de tarjetas CRC u otro método
donde se expresen claramente las clases y sus relaciones permiten crear análisis y
diseños robustos que dan respuesta a los problemas planteados en el sistema.

Otro método de AOO: Clases y su relación con los objetos.

Como sabemos la clase es una representación abstracta que describe a un conjunto


de objetos, estos objetos tienen en común una misma estructura (de datos) y un
mismo comportamiento (las mismas funciones), en otras palabras son la misma
cosa y hacen lo mismo.

En la fase de diseño de una programa o aplicación, el elemento fundamental son


determinar las clases; porque un conjunto de objetos iguales, debe ser representado
en forma abstracta por una clase, esta clase es la que vamos a programar en un
lenguaje de programación orientado a objeto (LOO) .

Diseño del programa.


Para diseñar un programa, se elabora o diseña el algoritmo que soluciona el
problema de tres partes:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 52


Primero se diseña el diagrama de clases
Segundo se diseña la lógica de las clases en pseudocódigo
Tercero se realiza la prueba con el lenguaje OO.

Como determinar las clases en los problemas de programación


Cuando hemos identificado los objetos del problema se procede a diseñar el
diagrama de clases, como dijimos los objetos serán las clases del problema, es decir
su plantilla o abstracción de objeto o clase, es recomendable dibujar la clase con
representación de algunos objetos, que en este diseño serán instancias de la clase

Observemos el siguiente ejemplo de una clase y algunas de sus instancias:

CLIENTE

Nombre
Dirección
….

ObjetoCliente ObjetoCliente ObjetoCliente

Nombre Juan Nombre Pedro Nombre María

Explicación

Se diseña la clase CLIENTE, de la cual se genera una instancia, que es el objeto


que representa al cliente Juan, otra instancia que genera al cliente Pedro, y así
sucesivamente.

Para diseñar una estructura de clase, se debe hacer dos cosas:

1.- Definir los datos que 2.- Definir los métodos u


representaran a los objetos de la operaciones que implementaran las
clase acciones de los objetos.

Los datos son de dos tipos Los métodos son de dos tipos

A.- el tipo de dato que entrara como A.- son los métodos que colocan o
materia prima, es decir que se establecen (setter) valores a los

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 53


deberán leer a través de un datos del objeto, ya sea a través de
dispositivo de entrada leerlos o mediante cálculos.

B.- El tipo de dato que se deben B.- Los métodos que acceden u
generar mediante cálculos u obtienen (getter) los valores de los
operaciones en los métodos datos para utilizarlos, ya sea para
realizar cálculos o darles salida.

Cómo identificar los métodos en una clase

Cuando realice el análisis del problema se buscan los verbos. Por lo general estos
son métodos u operaciones de la clase, por ejemplo: LeerLosDatos, ImprimirSalario,
VerificarId, etc. CalcularSalario, EncontrarIva

MUY IMPORTANTE:

Para establecer los valores de cada uno de los datos de un objeto, se


debe definir un método del objeto (Clase) que permita colocar (setter)
el valor a cada dato, ya sea que lo lea o que lo calcule

De igual forma para dar salida al valor de un dato se requiere un


método de acceder (getter) al valor del dato para darlo como salida,
uno para cada uno.

Por ejemplo, tenemos la clase de CLIENTE donde tenemos que calcular el saldo
del cliente, tenemos que cada objeto se representa mediante los datos:

NombreCliente --- Nombre del cliente


SaldoAnterior ---- Saldo antes del abono
Abono ---- Abono del mes
CuotaInteres ---- Calculo de interés
SaldoNuevo ---- Saldo actual

Entonces para cada dato se debe establecer un método setter y/o getter , en el
ejemplo se requieren los siguientes métodos:

EstablecerNombreEm( )  Para leer (entrada) el valor del dato nombre

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 54


EstablecerSaldoAnt( ) - Para leer (entrada) el Valor del dato Saldo Anterior
EstablecerAbono ( )  Para leer Abono el valor del dato abono del cliente
CalcularCuotaInte( ) - Calcular el valor del dato interés
CalcularNuevoSaldo( )  Calcular el dato nuevo saldo
Obtener(Nombre( )  Para acceder y visualizar (imprimir) el valor del
dato nombre
ObtenerNuevo Saldo( )  Para acceder y visualizar (imprimir) el valor del dato
Nuevo saldo.

Nota: Observe que el método setter inician su nombre con establecer o calcular
Los métodos getter inician con obtener

Algunas
Observe quecaracterísticas dedefine
no para todos los datos se la encapsulación
un método getter.

Modificadores de acceso (visibilidad)

Los símbolos - + # _ * sirven para indicar la visibilidad que tendrá cada dato o
método, se conocen como modificador de acceso:

Privado (-) Estos datos solo pueden ser vistos y utilizados por los
(Private) métodos de la misma clase. Por defecto los datos de
una clase son privadosa
Protegido ( # ) Pueden ser vistos y utilizados por métodos de la
(Protected) mmisma clase y por métodos de subclases derivadas
de la clase madre.
Publico (+) Pueden ser visto y utilizados tanto por métodos de la
(Public) clase, como por métodos de otra clase
Estático (_) Son únicos para toda la clase, es decir, no peaerteneen
(Static) a ninguna instancia (objeto) de la clase, pero pueden ser
utilizados por todas las instancias de la clase.
Abstracto ( * ) Los métodos que se declaran abstracto no tienen
( Abstract) implementación, por lo tanto deber ser implementados
en subclase
Como generar instancias de clases
Las clases definidas se utilizan para generar instancias u ocurrencias, estas
instancias son los objetos, que se utilizaran en el funcionamiento del programa,
esto significa que podemos ver la clase como un molde o plantilla o un tipo de
dato, que se utiliza para generar objetos específicos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 55


CLIENTE

Nombrecliente
SaldoAnterior
Abono

establecerNombreEmp()
establecerSaldoAnte()
establecerInteres()
calcularSaldoActual()

ObjetoCliente ObjetoCliente

NombreCliente NombreCliente
Juan Maria

SaldoAnterior SaldoAnterior
4574.50 12740.50

Abono Abono
560.00 6600.00

establecerNombreEmp() establecerNombreEmp()
establecerSaldoAnte() establecerSaldoAnte()
establecerInteres() establecerInteres()
calcularSaldoActual() calcularSaldoActual()

Explicación

En el ejemplo anterior podemos observar que tenemos la clase CLIENTE, la cual


genera una instancia que es el ObjetoCliente que representa a Juan, y así
sucesivamente hasta generar todas las instancias de la clase.

Puede observar que las instancias de la clase tienen los mismos tipos de datos y
métodos, pero NO la misma información

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 56


Como realizamos el programa orientado a objeto

Arquitectura modelo-vista-controlador
Un programa orientado a objeto que utilice la arquitectura modelo-vista-
controlador.

Esta formado por tres partes muy importantes:

1.- El modelo
Es la clase o conjunto de clases identificadas en el dominio del problema,
esta clase (o clases) representan al objeto u objetos presentes en el
problema

2.- La Vista o Interface grafica de usuario


Es la que el usuario observara en la pantalla, impresora u otro dispositivo
de salida de la computadora al operar el programa

3.- El controlador
Es la parte que permite que el usuario interactúe con la interface para
utilizar el modelo que representa y soluciona el problema planteado, puede
ser otra clase o varias

En programas complejos, la arquitectura modelo-vista-controlador se observa


asi:

CONTROLADOR

En programas
MODELOno muy complejos o que la vista INTERFAZ
es sencilla O
la VISTA
parte controlador se
combina con la interfaz y la arquitectura se simplifica:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 57


MODELO CONTROLADOR

Diseño de clases con algoritmos OO, utilizando el modelo- vista-


controlador.
Ejemplo Calcular el salario de un empleado, información a sacar por pantalla
Nombre del empleado y Salario semanal, datos conocidos : nombre, número de
horas trabajadas y pago por hora del empleado

El salario se calcula de la manera siguiente:

Si el número de horas trabajadas es mayor que 40, el excedente de 40 se paga al


doble de la cuota por hora, en caso de no ser mayor que 40 se paga a la cuota por
hora normal.

Realicemos la solución de acuerdo al modelo-vista-controlador

Solución
Primero: Se diseña el diagrama de clases

Empleado

NombreEmpleado
HorasTrabajadas
PagoHora
Salario EjecutaEmpleado

EstablecerNombre()
EstablecerHoras()
EstablecerPago()
CalcularSalario()
ObtenerNombre()
ObtenerSalario()

Explicación

Este diagrama consta de dos clases; una clase es la clase Empleado que es el
modelo que representa y soluciona el problema planteado; la otra es la clase
EjecutaEmpleado que es la clase controlador, la cual utiliza el modelo (la clase

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 58


Empleado) para controlar la interacción con el usuario representado y resolviendo
el problema

Segundo: Se diseña la lógica de las clases en pseudocódigo

Algoritmo Calcular Salario de un empleado

Clase Empleado
1.- Declaraciones
Datos
NombreEmpleado: Cadena
HorasTrabajadas: Entero
PagoHora: Real
Salario: Real

2.- Metodo EstablecerNombre( nom: cadena)


NombreEmpleado = nom
Fin Metodo EstablecerNombre

3.- Metodo Establecerhoras(horas: Entero)


HorasTrabajadas = horas
Fin Metodo EstablecerHoras

4.- Metodo EstablecerPago( pago: Real)


PagoHora = pago
Fin Metodo EstablecerPago

5.-Metodo CalcularSalario( )
If HorasTrabajadas<= 40 Then
Salario = HorasTrabajadas * PagoHora
Else
Salario = (40 * PagoHora) + (( HorasTrabajadas -40) *( PagoHora * 2))
Endif
Fin Metodo EstablecerNombre

6.- Metodo ObtenerNombre() : Cadena


Return NombreEmpleado
Fin Metodo ObtenerNombre

7.- Metodo ObtenerSalario( ) : Real


Return Salario
Fin Metodo ObtenerSalario

Fin de clase empleado

Clase EjecutaEmpleado

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 59


Metodo Principal
Declaraciones
Variables
NEmple : Cadena
HT: Entero
PagoH: Real
Declarar, crear e iniciar objeto
Empleado objEmpleado = new Empleado()
Solicitar nombre, número de horas, pago por hora
Leer NEmple, HT, PagoH
Establecer objempleado.EstablecerNombre(NEmple)
objEmpleado.EstablecerHoras(HT)
objEmpleado.EstablecerPago(PagoH)

Calcular ObjEmpleado.CalcularSalario()
Imprimir objEmpleado.ObtenerNombre()
objEmpleado.ObtenerSalario()
Fin Metodo principal
Fin clase EjecutaEmpleado

Tercero se realiza la prueba con el lenguaje OO. (! Esto se estudiara en la


Siguiente unidad ¡)

Diseño de algoritmo OO usando selección múltiple

Ejemplo:

Elaborar un algoritmo que dado un numero del 1 al 7, el programa imprima por


pantalla “Domingo ”,si es 1, “Lunes”, si es 2… “Sábado”, si es 7.

Solución:

Diagrama de Clases

PresentaDia

NumeroDia
NombreDia
EjecutaPresentaDia

EstablecerNDia()
CalcularNombreDia()
ObtenerNombreDia()
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 60
Segundo: Se diseña la lógica de las clases en pseudocódigo

Algoritmo PresentaDia de la semana

Clase PresentaDia
Declaraciones
Datos
NumDia : Entero
NombreDia : Cadena

Metodo EstablecerNDia( num: Entero)


NumDia = Num
Fin de método EstablecerDia

Metodo CalcularNombredia()
Swith NumDia
1: Nombredia = “Domimgo”
2: Nombredia = “Lunes”
3: Nombredia = “Martes”
4: Nombredia = “Miercoles”
5: Nombredia = “Jueves”
6: Nombredia = “Viernes”
7: Nombredia = “Sabado”
DEFAULT
NombreDia = “No está en el rango de 1 a 7 “
ENDSWITCH
Fin Metodo CalcularNombreDia

Metodo ObtenerNombreDia() : Cadena


Return NombreDia
Fin Metodo ObtenerDia

Fin clase PresentaDia

Clase EjecutaPresentaDia

Metodo Principal
Declaraciones
Variables
Ndia : Entero
Declarar, crear e iniciar objeto
PresentaDia Objdia = new PresentaDia
Solicitar numero de dia
Leer Ndia
Establecer Objdia.EstablecerNDia(Ndia)
Calcular ObjDia.CalcularNombreDia()
Obtener ObjDia.ObtenerNombreDia()

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 61


Fin Metodo Principal

Fin Clase EjecutaPresentaDia


Tercero se realiza la prueba con el lenguaje OO. (Esto se estudiara en la
Siguiente unidad ¡¡¡)

Diseño de algoritmo OO usando Estructura de repetición


DO…WHILE

Ejemplo:

Elaborar un algoritmo para calcular e imprimir el sueldo de varios empleado


de una empresa.

Datos disponibles: Nombre, Horas Trabajadas, Cuota por Hora


Proceso: Sueldo = Horas Trabajadas * cuota por Hora
Imprimir: Nombre, Sueldo.

Solución:
Diagrama de Clases

Empleado

NombreE
HorasT
PagoH
Sueldo

EstablecerNombreE() EjecutaEmpleado
EstablecerHorasT()
EstablecerPagoH()
CalcularSueldo()
ObtenerSueldo()
ObtenerNombreE()

Segundo: Se diseña la lógica de las clases en pseudocódigo

Clase Empleado
Declaraciones
Datos
NombreE : Cadena

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 62


HorasT : Entero
PagoH : Real
Sueldo : Real

Metodo EstablecerNombreE(nom : Cadena)


NombreE = nom
Fin método EstablecerNombreE

Metodo EstablecerHorasT (Horas : Enterol)


HorasT = Horas
Fin de método EstablecerHorasT.

Metodo EstablecerPagoH( Pago : Real)


PagoH = Pago
Fin Metodo EstablecerPagoH

Metodo CacularSueldo()
Sueldo = HorasT * PagoH
Fin método CalcularSueldo

Metodo ObtenerNombreE(): Cadena


Return NombreE
Fin Metoddo ObtenerNombreE

Metodo ObtenerSueldo() : Real


Return Sueldo
Fin método ObtenerSueldo
Fin Clase Empleado

Clase EjecutaEmpleado
Metodo Principal
Declaraciones
Variables
NomEmple : Cadena
HTraba : Entero
PagoHora : Real
Desea : Carácter

Do
Declarar, crear e iniciar objeto
Empleado objEmpleado = new Empleado()
Solicitar Nombre, horas trabajadas, cuota por hora
Leer nomEmple, HTraba,PagoHora
Establecer
ObjEmpleado.EstablecerNombreE(NomEmple)
ObjEmpleado.EstablecerHorasT(HTraba)
ObjEmpleado.EstablecerPagoH(PagoHora)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 63


Calcular ObjEmpleado.CalcularSueldo()
Imprimir ObjEmpleado.ObtenerNombreE()
ObjEmpleado.Obtenersueldo()
Preguntar “¿Desea procesar otro empleado (S/N) ?”
Leer Desea
WHILE Desea = “S”
Fin Metodo principal
Fin clase EjecutaEmpleado

Diseño de algoritmo OO usando arreglos unidimensionales

Ejemplo:

Se conoce el número de unidades producidas por un obrero en cada uno de los 30


días del mes. Elaborar un algoritmo que permita leer la producción de cada uno de
los 30 días y luego los visualice.

Solución
Diagrama de clases

Clase: Obrero
establecerProduccion()
EjecutaObrero
obtenerProduccion()

Algoritmo Obrero
Clase Obrero
1.- Declaraciones
Datos
Producción: Arreglo[30] : Entero
2.- Método establecerProduccion(pro[]: Entero)
Producción = pro
Fin método establecerProduccion
3.- Metodo obtenerProduccion(): Arreglo[] Entero
Return producción
Fin método obtenerProduccion
Fin Clase Obrero

Clase Ejecutaobrero
1.- Metodo principal
Declaraciones

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 64


Variables
Prod, prod2:arreglo[30] Entero
I : Entero
Declarar, crear e iniciar objeto
Obrero objObrero = new Obrero()
For i = 0; i<=29; i++
Solicitar producción del dia i +1
Leer prod[i ]
EndFor
Establecer
objObrero.establecerProduccion(prod)
Obtener
Prod2 = objObrero.obtenerProduccion()
For i = 0 ; i <= 29: i++
Imprimir prod[i]
EndFor
Fin Metodo principal
Fin Clase EjecutaObrero

Diseño de algoritmo OO usando herencia

Ejemplo:
En cierta empresa se tienen empleados; los empleado se dividen en dos tipos,
empleados por hora, a los que se les paga de acuerdo con el número de horas
trabajadas y a una cuota por hora. El otro tipo son los empleados asalariados, a
quienes se les paga de acuerdo a un sueldo fijo mensual.
Analisis, en este problema podemos identificar dos objetos :
Objeto EmpleadoPorHora
nombreEmpleado
deptoEmple
puestoTrabajo
horasTrabajo
cuotaHora
sueldoHoras

Objeto EmpleadoAsalariado
nombreEmpleado
deptoEmple
puestoTrabajo
sueldoMensual
sueldoQuincenal

Observamos que los objetos tienen datos en común, cuando se tiene una situación
como esta, podemos utilizar el mecanismo de herencia, mediante un proceso de
abstracción en el que definimos un objeto más abstracto que contenga en común a
los demás objetos, para uqe a partir de ese se deriven los otros objetos a utilizar.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 65


Empleado

EmpleadoPorHora EmpleadoAsalariado

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 66


Aplicando el diseño de estructura de clase tenemos:

Empleado

# nombreEmpleado
# deptoEmple
# puestoTrabajo EjecutaEmpleado

establecerNombre()
establecerDepto()
establecerPuesto()
obtenerNombre()
obtenerPuesto()
obtenerDpto()

EmpleadoPorHora EmpleadoAsalariado

horasTrabajadas SueldoQnalAsal
cuotaHora SueldoMensual
SueldoQnal
calcularSueldoQnalAsal()
establecerHoras() establecerSueldoMensual()
establecerCuota() obtenerSueldoQnalAsal()
calcularSueldoQnal()
obtenerSueldoQnal()

Diseño del algoritmo:

Algoritmo Calcular sueldo de varios empleados

Clase empleado
Declaraciones
Datos
# nombreEmpleado : cadena
# deptoEmple : cadena

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 67


# puestoTrabajo: cadena
Método establecerNombre(nom : cadena)
nombreEmpleado = nom
Fin método establecerNombre
Método establecerDepto(dep: cadena)
depatoEmple = dep
Fin de método establecerDepto

Método establecerPuesto(pues : cadena)


puestoTrabajo = pue
fin método establecerPuesto

Metodo obtenerNombre() : cadena


Return nombreEmpleado
Fin método obtenerNombre

Método obtenerPuesto() : cadena


Return puestoTrabajo
Fin método obtenerPuesto

Método obtenerDpto() : cadena


Return deptoEmple
Fin método obtenerDpto
Fin clase empleado

Clase EmpleadoPor Hora


Declaraciones
Datos
horasTrabajadas : Entero
cuotaHora : Real
SueldoQnal : Real

Metodo establecerHoras(horasT : Entero)


horasTrabajadas = horasT
Fin método establecerHoras

Metodo establecerCuota(cuotaH : Real)


cuotaHora = cuotaH
Fin método establecerCuota

Metodo calcularSueldoQnal()
SueldoQnal = horasTrabajadas * cuotaHora
Fin método CalcularSueldoQnal

Metodo obtenerSueldoQnal() : Real


Return sueldoQnal

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 68


Fin método obtenerSueldoQnal

Fin Clase EmpleadoPorHoras

Clase EmpleadoAsalariado
Declaraciones
Datos
SueldoQnalAsal : Real
SueldoMensual : Real

Método calcularrSueldoQnalAsal()
SueldoQnalAsal = SueldoMensual/2
Fin método calcularSueldoQnalAsal

Método establecerSueldoMensual(sdo : Real)


SueldoMensual = sdo
Fin método establecersueldoMensual

Metodo obtenerSueldoQnalAsal() : Real


Return SueldoQnalAsal
Fin método obtenerSueldoQnalAsal

Fin clase EmpleadoAsalariado

Clase EjecutaEmpleado
Metodo principal
Declaraciones
Variables
nomEmple, depto, puesto : cadena
hrsTra,TipoEmp : Entero
cuoH, SdoMen : Real
desea : carácter

Do
Imprimir menú y solicitar tipo de empleado
Tipos de empleados
1.- Empleado por Horas
2.- Empleado asalariado
Teclee tipo
Leer tipoEmp
Solicitar Nombre, departamento y puesto
Leer nomEmple, depto, puesto

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 69


If tipoEmple = 1 then
Crear objeto
EmpleadoPorHora objEmpleado = new empleadoPorHora()
Solicitar número de horas trabajadas y cuota por hora
Leer hrsTra, cuoH
Establecer
objEmpleado. establecerNombre(nomEmple)
objEmpleado.establecerDepto(depto)
objEmpleado.establecerPuesto(puesto)
objEmpleado. establecerHoras(hrsTra)
objEmpleado.establecerCuota(cuoH)
Calcular
objEmpleado. calcularSueldoQnal()
Visualizar
objEmpleado. obtenerNombre()
objempleado.obtenerPuesto()
objEmpleado.obtenerDpto()
objEmpleado. obtenerSueldoQnal()
Else
Crear objeto
EmpleadoAsalariado objEmpleado = new EmpleadoAsalariado()
Solicitar sueldo mensual
Leer SdoMen
Establecer
objEmpleado. establecerNombre(nomEmple)
objEmpleado.establecerDepto(depto)
objEmpleado.establecerPuesto(puesto)
objEmpleado. establecerSueldoMensual(SdoMen)
Calcular
objEmpleado. calcularSueldoQnalAsal()
Visualizar
objEmpleado. obtenerNombre()
objempleado.obtenerPuesto()
objEmpleado.obtenerDpto()
objEmpleado. obtenerSueldoQnalAsal()
Endif
Preguntar “¿Desea procesar otro empleado (S/N)? ”
Leer Desea
WHILE Desea = “S”
Fin metodo principal
Fin clase EjecutaEmpleado

Diseño de algoritmo OO usando polimorfismo

Ejemplo:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 70


El mismo ejercicio anterior, pero utilizando el concepto de polimorfismo

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 71


Empleado2

# nombreEmpleado
# deptoEmple
EjecutaEmpleado2
# puestoTrabajo
# SueldoQna

establecerNombre()
establecerDepto()
establecerPuesto()
calcularSueldoQna() **
obtenerNombre()
obtenerPuesto()
obtenerDpto()
obtenerSueldoQna()

EmpleadoPorHora2 EmpleadoAsalariado2
horasTrab SueldoMensual
cuotaHora
calcularSueldoQnalAsal()
establecerHoras()
establecerSueldoMensual()
establecerCuota()
calcularSueldoQnal()

Diseño del algoritmo

Algoritmo CALCULAR SUELDO DE VARIOS EMPLEADOS

Clase abstracta Empleado2


Declaraciones
Datos
# nombreEmpleado: Cadena
# deptoEmple : Cadena
# puestoTrabajo : Cadena
# SueldoQna: Real

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 72


Metodo establecerNombre(nom: Cadena)
nombreEmpleado = nom
Fin método establecerNombre

Método establecerDepto(dep: cadena)


deptoEmple = dep
Fin de método establecerDepto

Método establecerPuesto(pues : cadena)


puestoTrabajo = pue
fin método establecerPuesto

Metodo abstracto calcularSueldoQna()

Metodo obtenerNombre() : cadena


Return nombreEmpleado
Fin método obtenerNombre

Método obtenerPuesto() : cadena


Return puestoTrabajo
Fin método obtenerPuesto

Método obtenerDpto() : cadena


Return deptoEmple
Fin método obtenerDpto

Método obtenerSueldoQna() : Real


Return SueldoQna
Fin método obtenerDpto

Fin clase Empleado2

Clase EmpleadoPor Hora2 hereda de Empleado2


Declaraciones
Datos
horasTra : Entero
cuotaHora : Real

Metodo establecerHoras(horasT : Entero)


horasTrab = horasT
Fin método establecerHoras

Metodo establecerCuota(cuotaH : Real)


cuotaHora = cuotaH
Fin método establecerCuota

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 73


Metodo calcularSueldoQna()
SueldoQnal = horasTrabajadas * cuotaHora
Fin método CalcularSueldoQna

Fin Clase EmpleadoPorHora2

Clase EmpleadoAsalariado2
Declaraciones
Datos
SueldoMensual : Real

Método calcularrSueldoQnalAsal()
SueldoQnalAsal = SueldoMensual/2
Fin método calcularSueldoQnalAsal

Metodo obtenerSueldoQnalAsal() : Real


Return SueldoQnalAsal
Fin método obtenerSueldoQnalAsal

Fin clase EmpleadoAsalariado2

Clase EjecutaEmpleado2
Metodo principal
Declaraciones
Variables
nomEmple, depto, puesto : cadena
hrsTra,TipoEmp : Entero
cuoH, SdoMen : Real
desea : carácter

Do
Imprimir menú y solicitar tipo de empleado
Tipos de empleados
1.- Empleado por Horas
2.- Empleado asalariado
Teclee tipo
Leer tipoEmp
Solicitar Nombre, departamento y puesto
Leer nomEmple, depto, puesto
If tipoEmple = 1 then
Crear objeto
EmpleadoPorHora2 objEmpleado = new empleadoPorHora2()
Solicitar número de horas trabajadas y cuota por hora
Leer hrsTra, cuoH
Establecer
objEmpleado. establecerNombre(nomEmple)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 74


objEmpleado.establecerDepto(depto)
objEmpleado.establecerPuesto(puesto)
objEmpleado. establecerHoras(hrsTra)
objEmpleado.establecerCuota(cuoH)
Calcular
objEmpleado. calcularSueldoQnal()
Visualizar
objEmpleado. obtenerNombre()
objempleado.obtenerPuesto()
objEmpleado.obtenerDpto()
objEmpleado. obtenerSueldoQnal()
Else
Crear objeto
EmpleadoAsalariado2 objEmpleado = new EmpleadoAsalariado2()
Solicitar sueldo mensual
Leer SdoMen
Establecer
objEmpleado. establecerNombre(nomEmple)
objEmpleado.establecerDepto(depto)
objEmpleado.establecerPuesto(puesto)
objEmpleado. establecerSueldoMensual(SdoMen)
Calcular
objEmpleado. calcularSueldoQnalAsal()
Visualizar
objEmpleado. obtenerNombre()
objempleado.obtenerPuesto()
objEmpleado.obtenerDpto()
objEmpleado. obtenerSueldoQnalAsal()
Endif
Preguntar “¿Desea procesar otro empleado (S/N)? ”
Leer Desea
WHILE Desea = “S”
Fin método principal
Fin clase EjecutaEmpleado2

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 75


Resumen de la II Unidad

Sistemas de información
El analista en su desempeño realiza diferentes tipos de sistemas de
información, todo con el objetivo de satisfacer las demandas y/o necesidades
de cada nivel de una institución o empresa en la cual realiza su trabajo.

Entre los principales sistemas de información tenemos:


Sistemas de carácter transaccional
Sistemas de información general
Sistemas de soporte de decisiones
Sistemas estratégicos
Sistemas expertos

INTRODUCCION AL ANALISIS Y DISEÑO DE SISTEMAS

Conceptos de Análisis y Diseño Estructurado.

El diseño de arriba –abajo proporciona este método para descomponer un


problema dado en sus unidades componentes o módulos. Este diseño recibe
otros nombres tales como diseño estructurado, diseño compuesto, etc. Todas
estas metodologías describen la descomposición del problema en sus
funciones más importantes, la subdivisión de esas funciones en
subdivisiones y así sucesivamente

Reglas muy importantes

1.- Cada modulo debe ser independiente de los demás módulos.


2.- La responsabilidad operacional de cada modulo debe ser definida

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 76


concisamente.
3.- Cada modulo debe ofrecer solo un punto de entrada.

Análisis y Diseño Orientado a Objeto (ADOO)


El análisis orientado a objetos se basa en la solución del problema a partir de
objetos, es decir que la implementación del software será a partir de
comportamiento específicos de los objetos. Además los objetos tienen
procesos dinámicos en el análisis, estos pueden generar nuevos objetos,
crear nuevas relaciones entre los objetos, ser destruidos.

Es como analizar una estructura compleja, que se va armando por partes, sub
partes, sub sub partes, etc.

Capas del Análisis orientado a Objetos (AOO):


Capa de clases y objetos
Capa de estructura
Capa de atributos
Capa de servicios
Capa de tema

Metodologías de Análisis y Diseño Orientados a Objetos


El objetivo fundamental de un análisis del problema orientado a objeto (AOO)
es la definición de todas las clases que son relevantes para el mismo, sus
atributos y operaciones, las relaciones y demás elementos que determinan el
ámbito del problema…

Relaciones de Clases
Cuando modelamos objetos, las clases al igual que los objetos tienen
diferentes formas de relacionarse entre ellas, con el propósito de lograr los
objetivos propuestos de la aplicación de estudio.

Booch define las relaciones de clases de la siguiente forma:

Generalización/Especialización (es un)


Agregación (Todo-parte/Tiene un)
Asociación
Uso
Instanciación (Plantilla)
Metaclase

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 77


UML (Unified Modeling Lenguaje )
UML es lo más representativo de los métodos de análisis y diseño orientados
a objetos que aparecieron a finales de los ochenta y primeros años de los
noventa, expertos tales como Coad/Yourdon, Shlaer y Mellor, Booch, OMT,
Jacobson. Han realizado grandes aportes al análisis del modelado de datos.

Fichas o tarjetas CRC (clase, responsabilidad, colaborador)


El uso de fichas para representar las clases individuales es una técnica, de las
muchas que existen, que se utiliza para asignar responsabilidades a cada acción,
esta fichas se conocen como Tarjetas CRC (Beck 89) , una tarjeta CRC esta
dividida en tres partes

Clase: los nombres de las clases se crea el vocabulario con el que se formulara el
diseño.

Responsabilidades: Estas describen el problema que se va a resolver, deben


describir que se debe hacer y evitar los detalles de cómo se deben hacer.

Colaboradores: todos los objetos guardan relación con otro objeto del sistema.

Otro método de AOO: Clases y su relación con los objetos.

Diseño del programa.


Para diseñar un programa, se elabora o diseña el algoritmo que soluciona el
problema de tres partes:

Primero se diseña el diagrama de clases

Segundo se diseña la lógica de las clases en pseudocódigo

Tercero se realiza la prueba de escritorio.

Cuando realice el análisis del problema se buscan los verbos. Por lo general estos
son métodos u operaciones de la clase, por ejemplo:

LeerLosDatos()
ImprimirSalario()
VerificarId()
CalcularSalario()
EncontrarIva()

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 78


Para establecer los valores de cada uno de los datos de un objeto, se debe definir
un método del objeto (Clase) que permita colocar (setter) el valor a cada dato, ya
sea que lo lea o que lo calcule

De igual forma para dar salida al valor de un dato se requiere un método de acceder
(getter) al valor del dato para darlo como salida, uno para cada uno

Las clases definidas se utilizan para generar instancias u ocurrencias, estas


instancias son los objetos, que se utilizaran en el funcionamiento del programa,
esto significa que podemos ver la clase como un molde o plantilla o un tipo de dato,
que se utiliza para generar objetos específicos.

Un programa orientado a objeto que utilice la arquitectura modelo-vista-controlador


Está formado por tres partes muy importantes.

El modelo Es la clase o conjunto de clases identificadas en el dominio del problema,


esta clase (o clases) representan al objeto u objetos presentes en el problema

La Vista o interface gráfica o visualización.- Es la que el usuario observara en la


pantalla, impresora u otro dispositivo de salida de la computadora al operar el
programa

El controlador.- Es la parte que permite que el usuario interactúe con la interface


para utilizar el modelo que representa y soluciona el problema planteado, puede ser
otra clase o varias

Ejercicios de la II unidad.
Problemas para visualizar clases:

Dados los siguientes ejercicios encuentre:

a.- Definiciones de clases, utilizando la metodología CRC.


b.- Realice un diagrama de Generalización / Especialización si es necesario.
c.- Realice un diagrama de Agregación si es necesario
d.- Realice un diagrama de asociación de las clases encontradas.

Dados los siguientes ejercicios aplicar la arquitectura modelo-vista-


controlador para presentar la solución orientada a objeto:

1. Escribir un programa que visualice una tabla de los N primeros números, siendo
N un número que ingresa el usuario. Utilizar el siguiente diseño de salida
suponiendo que el usuario ingresó un tres:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 79


NÚMERO CUADRADO CUBO
1 1 1
2 4 8
3 9 27

2. Escribir un programa que permita registrar de los empleados de una fábrica (no
se sabe cuántos) su peso y saber cuántos pesan hasta 80 kg. inclusive y cuantos
pesan más de 80 kg.

3. En una tienda de artículos para caballeros al final del día se carga en la


computadora las boletas que confeccionaron los distintos vendedores para
saber cuanto fue la comisión del día de cada uno de ellos. Los datos que se
ingresan (por boleta) son: el número de vendedor y el importe. Cuando no hay
más boletas para cargar se ingresa 0. Teniendo en cuenta que el negocio tiene
3 vendedores y que el porcentaje sobre las ventas es del 5%, indicar cuánto
ganó cada vendedor en el día

4. Ingresar por teclado 3 números correspondientes a los lados de un triángulo.


Teniendo en cuenta que la suma de los dos lados menores tiene que ser superior
al lado mayor para que formen un triángulo, indicar si los números indicados
forman un triángulo y si lo forman que tipo de triángulo es (según sus lados).

5. Dados 3 números donde el primero y el último son límites de un intervalo, indicar


si el tercero pertenece a dicho intervalo

6. Por teclado se ingresa el valor hora de un empleado. Posteriormente se ingresa


el nombre del empleado, la antigüedad y la cantidad de horas trabajadas en el
mes. Se pide calcular el importe a cobrar teniendo en cuenta que al total que
resulta de multiplicar el valor hora por la cantidad de horas trabajadas, hay que
sumarle la cantidad de años trabajados multiplicados por $30, y al total de todas
esas operaciones restarle el 13% en concepto de descuentos. Imprimir el recibo
correspondiente con el nombre, la antigüedad, el valor hora, el total a cobrar en
bruto, el total de descuentos y el valor neto a cobrar.

7. Realizar la tabla de multiplicar de un número entre 0 y 10 de forma que se


visualice de la siguiente forma:
4x1= 4
4x2= 8
..........

8.- El Trabajo consiste en calcular calificaciones de los estudiantes del curso por
medio de dos formulas, la entrada del nombre del estudiante, código, código de la
clase y las calificaciones de cuatro exámenes, la ultima corresponde al examen final.

El profesor quiere utilizar dos formulas diferencias para calificar a los estudiantes,
ya que ellos provienen de dos diferente cursos, si el código de la clase es 1, el

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 80


examen final es el 40 % de la calificación y los otros tres exámenes el 60 %, si el
código de la clase es 2, todas las calificaciones son sumadas y divididas entre 4
para obtener una calificación promedio.

En la clase 1 si la calificación del alumno es mayor de 70, el estudiante obtiene


“APROBADO”, en caso contrario “REPROBADO”, en la clase 2 la calificación final
es el promedio de las cuatro.

9.- El problema es calcular las cuotas del sindicato, las entradas al problema
son: El nombre del empleado, puesto, salario por hora y código del sindicato. Solo
existen dos códigos del sindicato, 1 o 2 , Si el código es 1, la cuota del sindicato es
el 15 % del salario por hora mas C$ 2.00.

Por otro parte se necesita saber el total de aportaciones de los trabajadores con el
código 1. Los de categoría 2 esta divididos en dos tipo y cada uno debe ser tratado
en forma diferente, si el sueldo por hora es mayor de C$ 5.00, la cuota del sindicato
es del 40 % del salario mas C$3.50, si es menos se le cobra el 25 % del salario
más C$ 1.00.

También se debe saber el total de aportaciones de los trabajadores con código 2.,
imprimir los datos de los empleados con sus respectivas aportaciones.

10.-Se desea calcular el salario de los empleados, los datos de entrada del
problema son el nombre del empleado, las horas trabajadas, el pago por hora y las
deducciones de la semana, el salario bruto se calcula utilizando la siguiente formula
Sueldo bruto = horas * pago por hora ; Salario neto = Sueldo bruto – deducciones,
imprimir los detalles de los empleados y los totales correspondiente de salarios y
deducciones.

11.- Una empresa distribuidora de artículos de diversión desea crear tarjetas


que almacenen el nombre del artículo y el código del mismo. A partir de de esa clase
(llamada producto) derive dos clases que nombraremos discos de música y libros,
la clase disco de música tendrá el dato de duración de minutos, el precio y el
cantante, la clase libro, tendrá la información numero de paginas, precio, fecha de
publicación, cada una de las tres clases tendrá la función leer() y mostrar() ,para
visualizar datos.

12.- Una persona desea saber en qué día del mes realizó más gastos en
compras, para ello ingresa por teclado día a día lo que gastó por día, cargando un
vector definido en memoria. Puede haber varias o ninguna compra para un
determinado día. Informar cual fue el día de mayor gasto.

13.- Leer dos listas A y B de dimensión 10. Generar una tercera lista C de 100
elementos donde la componente C[ i ] sea igual al mínimo valor de A[ i ] y B[ i ].
Mostrar los tres vectores

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 81


14.- Leer 20 números enteros positivos. Mostrar la lista tal como fue ingresado y
luego mostrarla ordenada en forma decreciente.

15.- De los 100 empleados de una fábrica se registra: número de legajo (coincide
con el número de índice), edad y salario. Se pide:
Ingresar los datos correlativamente
Calcular la edad promedio informando número de legajo de los empleados cuya
edad supere el promedio

16.- Mismo enunciado al ejercicio anterior. Se pide:


Ingresar los datos en forma aleatoria. (se pide ingreso de número de legajo de 1 a
100, se posiciona en el elemento correspondiente y se ingresa edad y salario)
Calcular salario promedio informando número de legajo de aquellos cuyo salario
supere el promedio

17.- Se tiene un grupo de alumnos , los datos por cada alumno son:
Nombre, Sexo(M,F), Edad,, Estatura, Peso, Color de los ojos, (1 = azul, 2= café, 3=
otro ), Color del cabello (1 = castaño, 2=negro, 3 = otro)

Elaborar un programa que lea los datos de entrada y que proporcione


a) Un listado de las mujeres de cabello negro y ojos azules, que midan entre
1.65 m y 1.75 my que pesen menos de 55 kg.
b) Un listado de los hombres de ojos cafés de mas 1.70 m de estatura y que
pesen entre 60 y 70 kg.

18.- Elaborar un programa que lea los datos de varios estudiantes: Nombre y tres
calificaciones parciales, visualizar los siguientes datos:

Reporte de Calificaciones

Nombre Calif Final


X ----------------------------X 999.99
X-----------------------------X 999.99

X------------------------------X 999.99

Total Alumnos : 999

Para aprobar el curso, debe tener 70 o mas de promedio , en caso de haber


reprobado la calificación será NA (No Acreditado)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 82


19.- Elaborar un programa que contabilice una cuenta de cheques, al inicio se
le introduce el nombre del cuentahabiente y el saldo inicial. A continuación se puede
hacer depósitos y retiros. Cuando sea depósito se incrementa al saldo, y cuando
sea retiro se resta. Este programa terminara cuando ya no se desee hacer
movimientos entonces se requiere la visualización siguiente:

Estado de cuenta

Nombre Cuentahabiente: X------------------------------X


Saldo inicial: 99,999,999.99

Movimiento Deposito Retiro Saldo


------------------- ---------------- --------------- --------------
1 999,999.99 999,999.99
2 999,999.99 999,999.99
3 999,999.99 999,999.99
4 999,999.99 999,999.99
..

TOTALES 9,999,999.99 9,999,999.99 9,999,999.99

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 83


LENGUAJE VISUAL BASIC NET
Indice:
1.- Elementos básicos de Visual Basic NET pagina 5
1.1.-Introduccion a Visual Basic NET
1.2.- Plataforma .NET
1.3.- Entorno de ejecución CLR
1.4.- El Lenguaje Intermedio y el CLS
1.5.- La biblioteca de clases de .NET
1.6.-Los espacios de nombres
1.7.- Acceso a datos con ADO.NET
1.8.- Aplicaciones Windows Forms

2.- Elementos del Lenguaje Visual Basic pagina 11


2.1.- Variables Visual Basic NET
2.2.- Constantes en Visual Basic NET
2.3.- Listas enumeradas
2.4.- Estructuras
2.5.- Ambito de variables
2.6.- Operadores aritméticos
2.7.- Jerarquía de las operaciones
2.8.- Orden de las operaciones
2.9.- Comentarios en Visual Basic NET

3.- Programas, formas y componentes de Visual Basic NET pagina 20


3.1.- Programa ejemplo de Visual Basic NET
3.2.- Otros componentes
3.3.- Dos o más forms en Visual Basic NET

4.- Estructuras, ciclos, decisiones en visual Basic NET pagina 30


4.1.-Instrucciones condicionales en Visual Basic
4.2.- Operadores relacionales en Visual Basic
4.3.- Instrucciones If… Then Else en Visual Basic
4.4.- Condiciones compuestas en Visual Basic
4.5.- Instrucciones de control
4.6.- Ciclos For… To Next
4.7.- Ciclo Do… Loop While
4.8.- Arreglos en Visual Basic
4.9.- Funciones del lenguaje integradas
4.10.- Procedimientos o sub rutinas en Visual Basic

5.- Programando con controles en Visual Basic pagina 68


5.1- El cuadro de herramienta
5.2.-Controles Window Basicos
5.2.1.- Control formulario

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 84


5.2.2.- Control Label
5.2.3.- Control TextBox
5.2.4. -Control Button
5.2.5.- Control ListBox
5.2.6.- Control Combobox
5.2.7.- Control CheckBox
5.2.8.- Control CheckedListBox
5.2.9.- Controles RadioButton
5.2.10.- Control GroupBox
5.2.11.- Control VScrollBar, HScrollBar. TrackBar
5.2.12.- Controles tipo menú
5.3.- Foco de entrada
5.4.- Codificando con los eventos de controles
5.5.- Codificando otros eventos de control
5.6.- Orden de tabulación de los controles
5.7.- Funciones para presentar mensajes
5.7.1.- Funcion InputBox()
5.7.2- Funcion MsgBox()
5.8.- Controles avanzados de Visual Basic
5.8.1- Control temporizadores (Timer)
5.8.2- Control ImageList
5.8.3-Control ToolBar
5.8.4- Control StatusBar
5.8.5 Control DateTimePiker
5.8.6- Control NumericUpDown
5.8.7- Control DomainUpDown
5.8.8- Control MonthCalender
5.8.9- Control LinkLabel
5.8.10- Control NotifyIcon
5.8.11- Controles de Dialogos
5.8.12- Control FontDialog
5.8.13- Control ColorDialog
5.9.- Interfaces
5.10.- Creando programas MDI
5.11.-Control de excepciones
5.11.1- Tipos de errores
5.11.2.- Formas de control de excepciones
5.11.2.1- Control no estructurado
5.11.2.2- Control estructurado

6.- Programacion Orientada a Objeto (POO) en Visual Basic pagina 170


6.1.- Que es una clase
6.2.- Crear la primea clase
6.3.- Propiedades de solo lectura y escritura
6.4.- Agregar métodos a una clase
6.5.- Agregar evento a una clase
6.6.- Crear una instancia de clase

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 85


6.7.- Como utilizar los constructores
6.8.- Como utilizar los destructores
6.9.- Como utilizar los miembros datos compartidos
6.10.- Como utilizar los métodos compartidos
6.11.- Polimorfismo en Visual Basic NET
6.12.- Probar controladores de eventos
6.13.- Herencia de clases en Visual Basic NET

7.- Impresión en Visual Basic pagina 210


7.1.- La solucion: Como imprimir en .NET
7.2.- Las clases para imprimir en .NET
Clase PrintDocument
Clase PrintSetting
Clase PrintDialog
Clase PrintPreviewDialog
Clase PrintPreviewControl
7.4.- Conclusion para imprimir en VB net
7.5.-Hacer Crystal Report con DataSet en Visual Basic.NET
7.6.- Reportes en visual basic.net con Crystal Report
7.7.- Como crear un reporte (ReportViewer)
7.8.- Reportes con datos agrupados (Reporting Service)
7.9.- Dar formato a un reporte (Reporting Service)

8.- Formularios de interfaz múltiple (MDI) página 258


8.1.- Aplicaciones estilo SDI
8.2.- Aplicaciones estilo MD
8.3.- Creación de menú de tipo ventana en formularios MDI
8.4.- Bloqueo de opciones de menús en formularios MDI
8.5.- Recorrer formularios hijos de un MDI
8.6.- Comportamiento no modal
8.7.- Modal de un formulario
8.8.- Controles de cuadro de diálogos de sistema
8.9.- Formularios dependientes
8.10.- Validación de controles.

9.-Streams en .NET página 289


Las clases basadas en stream
Manejar unfichero usando FileStream
Manejar un fichero usando StreamReader y StreamWriter

10.- Colecciones de datos pagina 332


Tipos de colecciones
Tipos de datos de almaceniamiento de las colecciones
Clases bases para crear colecciones personalizadas

11.- GDI+ Sistema gráfico de Windows pagina 342


System.Drawing

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 86


12.- Operaciones de entrada y salida (I/O). pagina 368
System.IO
Objetos Stream
Clases TextReader y TextWriter
Manejo de datos binarios

13.- Ensamblados en Visual Basic Pagina 391

14 .-Crear un proyecto de instalación (Setup) Pagina 397

Adendum

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 87


1.- ELEMENTOS BASICOS DE VISUAL BASIC NET
1.1.- Introducción a Visual Basic NET

Información y Conocimiento son los dos elementos claves del nuevo milenio ninguna
sociedad podrá alcanzar ni puede ignorar este nuevo esquema ya las naciones no se miden
por su riqueza industrial, ni sus activos físicos, ni por su poder militar, sino por la cantidad
de información que produce y consume, así como por la recombinación de información nueva
en un conocimiento de grado superior.
Nuevos sistemas de información, tienden a ser cada vez de mayor alcance y complejidad
sobre todo cuando se toman en cuenta las nuevas necesidades de información y conocimiento
que demandan las nuevas organizaciones.

VISUAL BASIC NET es un lenguaje de programacion desarrollado por Microsoft muy


apropiado para construir sistemas de informacion basados en red o mejor aun en internet.

1.2.- Plataforma .NET

Es un amplio conjunto de bibliotecas o librerías de desarrollo que pueden ser utilizadas por
otras aplicaciones para acelerar enormemente el desarrollo y obtener de manera automática
características avanzadas de seguridad, rendimiento, etc... .NET permite compilar, depurar,y
ejecutar aplicaciones .NET.

Desde que apareció la primera versión de Microsoft.NET Framework 1.0 en Visual Studio
2002, hasta la última versión del 2010 se vienen realizando mejoras continuas que permiten
realizar una mejor integración de todos los componentes en aplicaciones mas robustas y
completas del mercado para la tecnología de desarrollo de Microsoft.

Microsoft.Net Framework es una apliacion que se iintegra en el entorno de desarrollo de forma


fácil y transparente al programador, el cualse utiliza para ayudarnos a desarrollar de forma
rápida, correcta, segura y en el menor tiempo posible nuestras aplicaciones.

1.3.- Entorno de ejecución CLR


.NET ofrece un entorno de ejecución para sus aplicaciones conocido como Common Language
Runtime o CLR. La CLR es la implementación de Microsoft de un estándar llamado Common
Language Infrastructure o CLI. Éste fue creado y promovido por la propia Microsoft pero
desde hace años es un estándar reconocido mundialmente por el ECMA.

El CLR/CLI esencialmente define un entorno de ejecución virtual independiente en el que


trabajan las aplicaciones escritas con cualquier lenguaje .NET. Este entorno virtual se ocupa
de multitud de cosas importantes para una aplicación: desde la gestión de la memoria y la vida
de los objetos hasta la seguridad y la gestión de subprocesos.

1.4.- El Lenguaje Intermedio y el CLS

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 88


Al contrario que otros entornos, la plataforma .NET no está atada a un determinado lenguaje
de programación ni favorece a uno determinado frente a otros. En la actualidad existen
implementaciones para varias decenas de lenguajes que permiten escribir aplicaciones para la
plataforma .NET. Los más conocidos son Visual Basic .NET, C# o J#, pero existen
implementaciones de todo tipo, incluso de ¡COBOL!.

Lo mejor de todo es que cualquier componente creado con uno de estos lenguajes puede ser
utilizado de forma transparente desde cualquier otro lenguaje .NET. Además, como ya se
ha comentado, es posible ejecutar el código .NET en diferentes plataformas y sistemas
operativos

1.5.- La biblioteca de clases de .NET


Todo lo que se ha estado comentando hasta ahora en el curso constituye la base de la
plataforma .NET. Si bien es muy interesante y fundamental, por sí mismo no nos serviría de
mucho para crear programas si debiésemos crear toda la funcionalidad desde cero.

Obviamente esto no es así, y la plataforma .NET nos ofrece infinidad de funcionalidades "de
fábrica" que se utilizan como punto de partida para crear las aplicaciones. Existen
funcionalidades básicas (por ejemplo todo lo relacionado con la E/S de datos o la seguridad)
y funcionalidades avanzadas en las que se fundamentan categorías enteras de aplicaciones
(acceso a datos, creación de aplicaciones Web...).

Toda esta funcionalidad está implementada en forma de bibliotecas de funciones que


físicamente se encuentran en diversas DLL (bibliotecas de enlazado dinámico).

A su conjunto se le denomina Base Classes Library (Biblioteca de clases base o BCL) y


forman parte integral de la plataforma .NET, es decir, no se trata de añadidos que se deban
obtener o adquirir aparte.

La siguiente figura ilustra a vista de pájaro la arquitectura conceptual de la plataforma .NET.


En ella se pueden observar los elementos que se han mencionado en apartados anteriores
(lenguajes, CLR, CLS...) y en qué lugar de se ubican las bibliotecas de clases base:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 89


Todo lo que se encuentra en la BCL forma parte de la plataforma .NET. De hecho existe tal
cantidad de funcionalidad integrada dentro de estas bibliotecas (hay decenas de miles de
clases) que el mayor esfuerzo que todo programador que se inicia en .NET debe hacer es el
aprendizaje de las más importantes. De todos modos Visual Studio ofrece mucha ayuda
contextual (documentación, Intellisense...) y una vez que se aprenden los rudimentos resulta
fácil ir avanzando en el conocimiento de la BCL a medida que lo vamos necesitando.

1.6.- Los espacios de nombres


Dada la ingente cantidad de clases que existen debe existir algún modo de organizarlas de un
modo coherente. Además hay que tener en cuenta que podemos adquirir más funcionalidades
(que se traducen en clases) a otros fabricantes, por no mencionar que crearemos
continuamente nuevas clases propias. Para solucionar este problema existen en todos los
lenguajes .NET los espacios de nombres o namespaces. Un espacio de nombres no es más
que un identificador que permite organizar de modo claro las clases que estén contenidas en
él así como otros espacios de nombres.

Así, por ejemplo, todo lo que tiene que ver con el manejo de estructuras de datos XML en la
plataforma .NET se encuentra bajo el espacio de nombres System.Xml. La funcionalidad
fundamental para crear aplicaciones Web está en el espacio de nombres System.Web. Éste a
su vez contiene otros espacios de nombres más

1.7.- Acceso a datos con ADO.NET

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 90


El acceso a fuentes de datos es algo indispensable en cualquier lenguaje o lataforma de
desarrollo. La parte de la BCL que se especializa en el acceso a datos se denomina de forma
genérica como ADO.NET.

Si usted ha programado con Visual Basic 6.0 o con ASP, ha empleado en su código con total
seguridad la interfaz de acceso a datos conocida como ADO (ActiveX Data Objects), puede
que combinado con ODBC (Open Database Connectivity). Si además es usted de los
programadores con solera y lleva unos cuantos años en esto es probable que haya usado RDO
o incluso DAO, todos ellos métodos mucho más antiguos.

ADO.NET ofrece una funcionalidad completamente nueva, que tiene poco que ver con lo
existente hasta la fecha en el mercado. Sin embargo, con el ánimo de retirar barreras a su
aprendizaje, Microsoft denominó a su nuevo modelo de acceso a datos con un nombre similar
y algunas de sus clases recuerdan a objetos de propósito análogo en el vetusto ADO.

ADO.NET es un modelo de acceso mucho más orientado al trabajo desconectado de las


fuentes de datos de lo que nunca fue ADO. Si bien este último ofrecía la posibilidad de
desconectar los Recordsets y ofrecía una forma de serialización de estos a través de las
diferentes capas de una aplicación, el mecanismo no es ni de lejos tan potente como el que
nos ofrece ADO.NET.

El objeto más importante a la hora de trabajar con el nuevo modelo de acceso a datos es el
DataSet. Sin exagerar demasiado podríamos calificarlo casi como un motor de datos
relacionales en memoria. Aunque hay quien lo asimila a los clásicos Recordsets su
funcionalidad va mucho más allá como se verá en el correspondiente módulo.

1.8.- Aplicaciones Windows Forms


Las aplicaciones de escritorio son aquellas basadas en ventanas y controles comunes de
Windows que se ejecutan en local. Son el mismo tipo de aplicaciones que antes construiríamos
con Visual Basic 6 u otros entornos similares.

En la plataforma .NET el espacio de nombres que ofrece las clases necesarias para construir
aplicaciones de escritorio bajo Windows se denomina Windows Forms. Este es también el
nombre genérico que se le otorga ahora a este tipo de programas basados en ventanas.

Windows Forms está constituido por multitud de clases especializadas que ofrecen
funcionalidades para el trabajo con ventanas, botones, rejillas, campos de texto y todo este
tipo de controles habituales en las aplicaciones de escritorio. Visual Studio ofrece todo lo
necesario para crear visualmente este tipo de programas, de un modo similar aunque más
rico al que ofrecía el entorno de desarrollo integrado de Visual Basic.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 91


Diseñador de interfaces de aplicaciones de escritorio con Windows Forms en Visual Studio

Este es el aspecto que presenta parte del código que genera la interfaz mostrada en la
anterior figura:

2.- Elementos del Lenguaje Visual Basic


2.1.- VARIABLES VISUAL BASIC NET

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 92


Identificadores son conjuntos de letras y/o numeros que se utilizan para simbolizar todos los
elementos que en un programa, son definibles por el usuario (programador o ingeniero de
software) del mismo, como son las variables donde se almacenan datos, funciones (pequenos
modulos con codigo), etiquetas, clases, objetos, etc.

En VISUAL BASIC NET un identificador es una palabra compuesta de letras y/o numeros
de hasta 32 caracteres significativos, empezando siempre con una letra.

Una variable se define como un identificador que se utiliza para almacenar todos los datos
generados durante la ejecucion de un programa.

Existen ciertas reglas en cuanto a variables:

 Claras y con referencia directa al problema.


 No hay espacios en blanco, ni simbolos extraños en ellas.
 Se pueden usar abreviaturas, pero solo de caracter general.
 No usar palabras reservadas del lenguaje.

Ejemplos de buenas variables:

Nombre, Edad, SdoDiario, IngMensual, Perimetro, Calif1, etc.

2.1.1.- Declaracion y tipos de datos

En Visual Basic NET a toda variable que se use en un programa, se le debe asociar
(generalmente al principio del programa) un tipo de dato especifico.

Un tipo de dato define todo el posible rango de valores que una variable puede tomar al
momento de ejecucion del programa y a lo largo de toda la vida util del propio programa.
Los tipos de datos más comunes en Visual Basic NET son:

Tipo Rango
BYTE 0-255
INTEGER(%) +-2,147,483,698
SINGLE(!) 3.4E+-38(7 DECIMALES)
DOUBLE(#) 1.8E+308(16 DECIMALES)
CURRENCY 15 DIG IZQ 4 DIG DEECHA
STRING($) 2 BILLONES CHARS
BOOLEAN TRUE, FALSE
DATE FECHA
VARIANT TODOS LOS TIPOS y mas usado en este curso

Recordar Tambien que en Visual Basic NET toda variable usada en un programa se debera
declarar al principio del programa el formato de declaracion mas sencillo es:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 93


DIM VARIABLE AS TIPO
Ejemplos
DIM vVALOR AS INTEGER
DIM vVALOR AS LONG, BETA AS LONG
DIM vVALOR AS INTEGER, sNOMBRE AS STRING
DIM sCIUDAD AS STRING * 20, ALFA AS DOUBLE

Observar último caso de ciudad asi de esta manera se consigue una string de tamano definido.

En Visual Basic NET un problema comun a lo largo de este curso, es la necesidad de convertir
variables numericas a strings y tambien el problema inverso es decir convertir strings a su
representacion numerica.

Para este último problema por ejemplo se tiene:

DIM VPI AS STRING


VPI = “3.1416”

Como se observa del ejemplo anterior, se puede dar en algun momento la necesidad de
convertir la string VPI a su valor numerico, para resolver este problema se deberan usar las
siguientes funciones de conversion numerica que proporciona Visual Basic NET.

En Visual Basic NET se tendria:

DIM ALFA AS STRING


DIM BETA AS SINGLE Nota: Estamos usando una
ALFA = “3.1416” función de Visual Basic para
BETA= CINT (ALFA) tomar solo el valor entero de
ALFA
Tambien podemos declarar variables utilizando unos símbolos o caracteres detrás de las
variables que indiquen el tipo de variable utilizada, la tabla muestra estos símbolos:

Tipo de dato Simbolo Caracter


Short S
Integer % I
Long & L
Single ! F
Double # R
Decimal D
UShort US
UInteger UI
Ulong UL
String $

Tipos de datos Objetos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 94


Object es un tipo de datos de forma implicitay del cual heredan el resto de tipos de datos

2.2.- Constantes en Visual Basic NET

Formato:
Const variables As tipo = valor
Ejemplos

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click

Const vPI as double = 3.1416


Dim valor As decimal
Valor = (2 * vPI) ^2
MessageBox.show(Valor)
End sub

2.3.- Listas enumeradas


Son listas de variables o datos que hacen referencia a índices y estos empiezan desde 0 en
adelante. El formato que se utiliza es el siguiente:

Private Enum <Nombre_Variable> As <Tipo_Dato>


<Variable> = Valor_asignado

End Enum

Observemos el siguiente ejemplo:


Private Enum valores As Integer
Valor1 = 3
Valor2 = 5
Valor3 = 7
End Enum

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click

Dim valor As valores


Valor = valores.valor2
MessageBox.show(Valor)
End sub

Nota: Si deseamos conocer el nombre de la variable seleccionada de la lista enumerada,


podemos utilizar:
Dim valor As valores
Valor = valores.valor2

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 95


MessageBox.show(Valor.ToString() & “: “ & Valor)

Se presentara: valor2: 5

2.4.- Estructuras en Visual Basic


Las estructuras están formadas por uno o mas miembros y cada miembro puede ser de un
tipo de datos determinado. El formato a utilizar es:

Structure <nombre>
Public <nombre> As <tipo>
End Structure

Ejemplo de uso de estructura:

Private Structure Alumno


Public nombre As String
Public Edad As Integer
Public Id As String
End Structure

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click

Dim MiAlumno As Alumno


MiAlumno.nombre = “Carlos “
MiAlumno.edad = 23
Mialumno.Id = “2011-23056”
MessageBox.show(MiAlumno.nombre & “ tiene “ & MiAlumno.edad & “ años”)
End sub

Se presentara en pantalla: Carlos tiene 23 años

Tambien podemos utilizar la palabra reservada With para realizar acciones que se repiten,
evitando escribir una parte del código, analicemos el siguiente ejemplo:

Private Structure Alumno


Public nombre As String
Public Edad As Integer
Public Id As String
End Structure

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 96


Dim MiAlumno As Alumno
With MiAlumno
.nombre = “Carlos “
.edad = 23
.Id = “2011-23056”
MessageBox.show(MiAlumno.nombre & “ tiene “ & MiAlumno.edad & “ años”)
End sub

2.5.- Ambito de variables en Visual Basic

El lugar donde sea declarada una variable afectara el uso que el programa quiera hacer de
esa variable. Las reglas basicas que determinan como una variable puede ser usada
depende del lugar donde se puede declarar una variable. Veamos la siguiente tabla:

Declaración Lugar de Declaración Alcance o Ámbito

Public Módulo o Clase Global, en todo el proyecto.


Protected Clase En la clase declarada o en una derivada.
Friend Clase En el Assemblie.
Private Módulo Solo en el módulo.
Dim Procedimiento Solo en el Procedimiento.
Static Procedimiento Solo en el Procedimiento.

En escencia una variable local solo es conocida por el codigo de esa funcion o procedimiento
y es desconocida por otras funciones o procedimientos.

En la programacion formal no es acostumbrado usar muchas variables globales por varias


razones, una de ellas es que variables globales estan vivas todo el tiempo de ejecucion del
programa.

Si una variable global solo la ocupa unos cuantos procedimientos no tiene caso que este
viva para todo el resto, otra razon es que es peligroso tener variables globales porque todo
el conjunto de procedimiento y funciones que componen un programa tienen acceso o
comparten su valor y se corre el riesgo de que inadvertidamente alguno de ellos modifique
su valor.

Programa

' Creando y cargando una variable global

Dim varglobaluno as integer = 50 ‘Fuera de todo procedimiento

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 97


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
' creando, cargando y mandando una var local Este es un
Dim varlocaldos = 20 procedimiento
Call PROC1(varlocaldos) en Visual Basic
End Sub NET

Sub PROC1(ByVal varlocaltres As Single)


'aqui se puede usar varglobaluno por ser global
'y varlocaltres por ser local pero no se puede usar varlocaldos
' porque es local en otro procedimiento
Label1.Text = varglobaluno + varlocaltres
End Sub

2.6.-- Operadores aritmeticos


En Visual Basic NET un operador es un simbolo especial que indica al compilador que debe
efectuar una operacion matematica o logica.

Visual Basic reconoce los siguientes operadores aritmeticos:

OPERADOR OPERACIÓN
+ Suma
- Resta
* Multiplicacion
/ Division flotante
\ Division Entera
^ Potencia
MOD Modulo

El Operador (/) Division Flotante es el operador de division normal.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 98


El Operador (\) tambien es division pero los datos:
a) Primero son redondeados al entero más cercano (byte, integer, long)
b) Al final visual basic trunca la parte residual.
El Operador (^), resuelve dos problemas:

a) Ejemplo 5 2 se resuelve enVisual Basic NET:

dim alfa as integer 9


alfa = 5 ^ 2

Desplegar alfa, sale 9 en pantalla

b) Ejemplo para Raices solo recordar la ley de exponentes que dice:

Para estos casos:

= 5^8/3

= 9^1/2

En Visual Basic el operador (MOD) devuelve el residuo entero de una division entre enteros,
ejemplo:

Dim alfa As Single 3


alfa = 23 MOD 4
Visualizar alfa; El resultado en pantalla es 3

Otro ejemplo;
8
alfa = 108 MOD 10

Visualizar alfa; El resultado en pantalla es 8

Actividades de reforzamiento de lo aprendido

Ejercicios de programacion

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 99


Resolver algebraicamente en papel las siguientes ecuaciones expresándolas en formato de
Visual Basic NET

1.-

2.-

3.-

2.7.- Jerarquia de operaciones

En Visual Basic NET el problema de no tomar en cuenta la jerarquia de los operadores al


plantear y resolver una operacion casi siempre conduce a resultados muchas veces
equivocados como estos:

Ejemplos:

a) 2 + 3 * 4 = 20 (incorrecto)

2 + 3 * 4 = 14 (correcto)

b) si calif1 = 60 y calif2 = 80 ; Entonces si en programa se usa

promedio = calif1 + calif2/2 ; Da como resultado promedio = 100

En Visual Basic NET recordar siempre, que antes de plantear una formula en un programa
se debera evaluar respecto al orden siguiente:

2.8.- Orden de operaciones:

1.- Parentesis
Ordenes de
2.- Potencias y raices operacion

3.- Multiplicaciones y divisiones

4.- Sumas y restas

5.- Dos o más de la misma jerarquia u orden, entonces resolver de izquierda a derecha

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 100


Nota: Si se quiere alterar el orden normal de operaciones, entonces usar
parentesis.

Nota: Tampoco es bueno usar parentesis cuando no es necesario en una


operacion, esto solo indica que no se evaluo bien la formula

Ejemplo:

area = ( base * altura ) / 2

Aqui los parentesis estan de mas porque por orden de operaciones, multiplicacion y division
tienen la misma jerarquia y entonces se resuelven de izquierda a derecha en otras palabras
en visual basic NET ni que falten parentesis ni que sobren parentesis

2.9.- Comentarios en Visual Basic NET


Para agregar comentarios a nuestro código de programa podemos hacerlo de variasm
maneras:
1.- Utilizando el carácter ‘

area = base * altura / 2 ‘ Encontramos el área del cuadrado

2.- Utilizando la palabra reservada REM, se utiliza al comienzo de una línea:

Rem Encontramos el área del cuadrado


area = base * altura / 2

3.- Cuando queremos utilizar pequeñas porciones de regiones de comentarios y código que
se puede contraer y expandir, el formato a utilizar es:

#Region “ < texto >”


… Aquí se escribe lo que quermos poner como comentario en varia líneas
… Se puede escribir líneas de codigo
#End Region

Ejemplo:

#Region “ Problema 1”
‘El problema permite encontrar el Mayor de los números de una lista
‘Proporcionada por el usuario
Dim IValor As Integer = 0
#En Region

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 101


MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 102
3.- PROGRAMAS, FORMAS y COMPONENTES VISUAL BASIC NET
Recordar que programas visuales, se construyen usando los siguientes elementos:

1.- Un objeto ventana o form1

2.- Objetos que permitan capturar y desplegar datos, de momento se usaran los dos
objetos de entrada / salida más comunes:

2.1 Objeto label Permite desplegar textos o mensajes estaticos

2.2 Objeto textbox Permite tanto capturar datos, asi como desplegar el resultado de
operaciones (recordar que textbox's) solo capturan o despliegan un dato a la vez, recordar
tambien que todos los datos que entren y salgan de un textbox o un label son de tipo string.

2.3.- Objetos InputBox() Para obtener datos directos y sencillos del usuario

2.4.- Objetos MessageBox() Para presentar informacion relevante al usuario

3.- Objeto Button Es el componente principal de la forma, contiene el código principal del
programa y su activación por el usuario provoca que se realicen los principales procesos del
problema planteado (aquí es donde se capturan datos, se realizan operaciones, etc.).

De este componente se maneja su propiedad Text para etiquetarlo con la palabra “OK” o
“ACEPTAR” o “EXE” y su evento Click para activarlo, es en dicho evento donde se
construirá muchas veces el código del programa.

Nota importante: Recordar que aunque no es un componente necesario en los


programas ya que el código se puede asociar o pegar a cualquier evento de
cualquier forma o componente del programa, Microsoft ya acostumbro a todos
los usuarios al boton OK, de acuerdo, OK.

RECORDAR que todos los componentes vistos incluyendo el propio form y ventana estos
tienen muchas propiedades que se pueden asignar o modificar y tambien tienen muchos
eventos a los cuales les podemos asociar o cargar el codigo del programa, todos estas
propiedades y eventos las podemos accesar dentro de la ventana de propiedades.

No olvidar que las palabras reservadas del lenguaje NO se deben utilizar como
variables, esto producirá un error en al aplicacion

Regresando a Form1, es sobre esta forma donde se construira el programa y esta forma se
convierte en ventana al momento de ejecutarse el programa.

Es decir sera la primera ventana que el usuario ve al momento de ejecutarse el programa, su


nombre es Form1.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 103


Esta forma o ventana es un objeto de VISUAL BASIC NET y como todos los
objetos de Visual Basic y del universo, la forma o ventana tiene asociados
propiedades y eventos.

Propiedades: Son todas las caracteristicas particulares que diferencian un objeto de otro
objeto, las propiedades o caracteristicas mas comunes son forma, tamano, color, etc., para
objetos en visual basic, estas propiedades se modifican o individualizan usando la PAGINA
DE PROPIEDADES, que es la parte del programa que las contiene.

Recordar que se pueden modificar las propiedades dentro de un programa, usando


instrucciones apropiadas, mismas que llevan el siguiente formato:

NomObjeto.Propiedad = nvovalor;
Ejemplo: Form2.BackColor = Yellow

Eventos: son todos aquellos sucesos de caracter externo que afectan o llaman la atencion
del objeto, para estos casos la forma o ventana u objeto:

1. Debe tener capacidad de detectar el evento


2. Aun más importante debe tener capacidad de reaccionar y emitir una respuesta,
mensaje o conducta apropiada al evento detectado.

Evento es por ejemplo que otro objeto llamado humano pulse el objeto tecla ESC, o haga
click derecho con el objeto raton en alguna parte de la ventana, etc. es en estos casos, cuando
la ventana u objeto detecte un evento de estos la propia forma u objeto debera responder de
manera apropiada.

Nota: Esta respuesta no es automatica, sino son la serie de instrucciones del lenguaje
(o programa) que los ingenieros de software diseñan (o programan) en otras palabras
son los eventos quienes contendran los programas.

Es tambien la VENTANA DE PROPIEDADES, quien contiene todos los posibles eventos


asociados a la forma.

Para los primeros programas en VISUAL BASIC solo se usaran propiedades sencillas como
color, font, etc. de Form1 y los objetos ya mencionados (LABEL, TEXTBOX, BUTTON,
INPUTBOX, MESSAGEBOX, LISTBOX, COMBOBOX) y no se usan de momento los
eventos que puede detectar Form1.

3.1.- Programa ejemplo Visual Basic NET

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 104


Resolvemos el problema de calcular el área de un triangulo con la formula área = base *
altura /2

Para resolver este problema se ocuparan los siguientes objetos. (para realizar el disño)

1.- Una ventana de windows (form1) para contener a todo el resto de componentes.

2.- Tres label's o etiquetas para desplegar mensajes apropiados al problema.

3.- Tres componentes TEXTBOX dos para capturar datos (base y altura) y el tercero para
desplegar el resultado (area).

4.- Un componente BUTTON para que active y contenga el codigo del problema y/o
programa.

Procedimiento detallado

1.- Crear un folder o directorio en su disco duro C:\ llamado PROGRAM1

2.- Cargar VISUAL BASIC desde la barra de start de windows

3.- Usar la opción FILE –> NEW PROJECT –> WINDOWS APPLICATION

4.-Usar Ahora la opcion FILE –> SAVEALL De la pantalla de grabación que sale ponerle
un nombre al proyecto (dejar el default ) y apuntarlo al directorio que se hizo de programas:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 105


5.- Queda ahora la pantalla de trabajo o diseno o construccion del programa

Recordar que pueden agregar TOOLBOX, (VENTANA DE PROPIEDADES Y


EXPLORADOR DE SOLUCIONES) usando la opción VIEW de la barra del menú.

6.- Observar que en grafica de arriba esta seleccionada la propia forma o ventana.

Dentro del programa se estarán cargando todos los objetos que usa el programa y por ejemplo
Visual Basic NET a los dos textbox's que se estarán usando los nombra por DEFAULT
como TextBox1 y TextBox2, con esas mayúsculas y minúsculas así que estará dificil estar
recordando su nombre por defecto

Es conveniente estar usando la propiedad NAME de todos los objetos sobre todo
textbox y label que se coloquen en una forma o ventana.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 106


Es decir es mas fácil construir una formula que diga num1.Text = num2.Text + 5 a el
original que seria TextBox1.Text = TextBox2.Text + 5 por esta razón es conveniente
asignarle un nombre relevante a cada TextBox usando la propiedad NAME de la pagina de
propiedades, en este curso se les asigna NAME a todos los textbox's y muchos de los otros
componentes que se usan.

7.- Arrastrar y acomodar desde la CAJA DE HERRAMIENTAS a FORM1 3 (tres)


compontes LABEL y cargarles su PROPIEDAD TEXT con las palabras BASE, ALTURA y
AREA respectivamente para escribir esto solo hacerlo usando la cajita que esta a un lado de
la propiedad dentro dela pagina de propiedades.

NOTA: si de alguna manera el editor los manda al código del programa,


observar que arriba de FORM1 hay tres pestañas:

FORM1.VB la que contiener el codigo del programa en los procedimientos y


eventos
FORM1 DESIGN que contiene el diseño
START PAGE contiene las caracteristicas de la pagina de inicio
De solo click en form1 design para regresar al ambiente visual.

8.- Arrastrar y acomodar ahora tres componentes textBox de los cuales en su propiedad
TEXT, limpiarla y dejarla en blanco y en su propiedad (NAME) cargarlos con las palabras
BASE, ALTURA y AREA respectivamente.

9.- Arrastrar y acomodar ahora un componente o control BUTTON, poner su propiedad


text=OK.

La pantalla diseñada es: 10.-Colocaremos el siguiente codigo


dentro del evento click de BUTTON

Private Sub Button1_Click(ByVal


sender As System.Object, ByVal e As
System.EventArgs) Handles
Button1.Click

AREA.Text=(BASE.Text*ALTURA.Te
xt / 2)
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 107


Para escribir este código solo haga CLIK dentro de BUTTON1 y VISUAL BASIC los
mandara a la pantalla de código, donde ya estará cargado el evento button1_clik(){}.

Atención solo se escribe el código en rojo, el evento button1.click(){} ya lo


escribe visual basic por default y respetar todas las mayusculas y minusculas
dentro del codigo.

Los dos parámetros que van dentro de button_click (OBJETO, variable e)–> son para
indicarle al compilador que se estarán enviando OBJETOS entre la forma o ventana y el
usuario del programa ( LOS TEXTBOXS son los objetos y primero se mandan vacios al
usuario y luego el sistema los recoge con datos desde el usuario).

La VARIABLE “e” (environment) es donde el sistema o compilador los va almacenando


temporalmente, si ya vieron algo de msdos y conocen el comando set ahí observaran los
textbox's con sus datos.

Regresando al código:

a.- Son las propiedades TEXT de los TEXTBOX'S quienes contienen los datos tanto
capturados como los de salida.

b.- Recordar además que cualquier propiedad TEXT de cualquier CONTROL o


COMPONENTE solo maneja datos de tipo TEXTO o STRING y por tanto para poder
realizar operaciones con los TEXTBOX.TEXT visual basic NET internamente los convierte
a los tipos apropiados.

c.- [VARNUMERICA COMPONENTE EXPRESION] .ToString() –> se uso para convertir


el valor numérico a tipo string Y PODERLO FORMATEAR para que salga el resultado con
dos decimales ( este tema de formateo se ve en el tema siguiente), para poderlo almacenar en
la propiedad TEXT del TEXTBOX.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 108


11.- Ya cargada la forma con sus componente y el evento click con su código respectivo,
grabar el programa con la opción FILE→SAVE o usar el icono de grabación (el disquito o
disquitos que esta en la barra de iconos arriba) y luego ejecutar el programa usando el icono
de RUN que también se encuentra en la barra de herramientas arriba o DEBUG START
o F5.

12.- El programa en ejecucion:

Nota: Si buscan muy bien dentro del folder


project1 se encontraran con muchos
archivos que creo VISUAL BASIC, dos de
ellos son los interesantes:

FORM1.VB que contiene todo el código


fuente, es decir el programa original y
WINDOWSAPPLICATION1.EXE
(dentro del folder bin\debug) que es el
archivo ejecutable, basta darle un click
desde el explorer de windows y se ejecutara
solo sin necesidad de que este cargado el
compilador de visual basic.

3.2.- Otros componentes Visual Basic

En este tema analizamos algunas instrucciones de VISUAL BASIC que nos permitirán
facilitar algunas tareas que están pendientes y también algunos controles y componentes que
también nos darán buena ayuda.

Formateo de datos numericos


Como se observa en los aplicaciones ya construidas los formatos numéricos de salida dejan
mucho que desear, para corregir esta situación, solo basta agregar una string de control dentro
del paréntesis de ToString(“strcontrol”) que son una serie de caracteres especiales que
proporciona la plataforma NET.

Ejemplo;

Double alfa = 3456.678 * 21.456 / 73.78902

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 109


Es claro que cuando esta variable alfa se mande a un textbox o un label el valor numérico
desplegado contendrá un montón de valores decimales, para mandar solo la cantidad de
decimales apropiados, solo usar la string de control con los caracteres apropiados ej;

Label1.Text = alfa.ToString(”#.##”)

Esta instrucción desplegara el resultado con solo dos decimales como resultado, si buscamos
la documentación de Visual Basic, esta nos muestra todos los posibles caracteres que se
pueden incluir en la string de control.

User-Defined Numeric Formats (Format Function)

3.3.-Dos o más forms en Visual Basic NET

El siguiente problema común, con el manejo de programas en VISUAL BASIC, es el de poder


crear, controlar y administrar mas de dos forms a la vez.

En este ejemplo o tema se crea un segundo form en diseño.

IMPORTANTE: TODOS LOS COMPONENTES LABEL'S TEXTBOX'S BUTTON'S, etc. que se


coloquen dentro de una forma o ventana deberan de asignarles su propiedad (NAME), es
decir VISUAL BASIC por default si se pone un label en la primera ventana (Form1) le asigna
el nombre de label1, si también se coloca otra label en la segunda ventana (Form2) también
le asignara el nombre de label1 y cuando se este ejecutando el programa y se codifique una
referencia a label1 visual basic tendrá problemas para conocer de cual label se está
tratando.

Para resolver este problema la referencia deberá realizarse usando el formato

NOMBREFORMA.NOMBRECOMPONENTE.NOMBREPROPIEDAD

También es recomendable usar la propiedad NAME para todos los componentes


que se usen dentro de una forma.

a) Crear un proyecto normal con su FORM1 normal.

b) Ahora se crea un segundo FORM2 o ventana, para lograr esto solo usar la opción
PROJECT→ADD NEW→WINDOWSFORM y seleccionar windowsform y observar y tratar
de usar algunos de los otros tipos de forma que ya trae incorporado visual basic .

Esta opción solo se muestra cuando ya se creó un proyecto, observar también que en el
ADMINISTRADOR DE PROYECTOS aparece registradas los dos forms FORM1.vb y FORM2.vb.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 110


c) Solo hacer click en form2.vb en el administrador de proyectos (o usar la pestaña arriba
en el compilador que ya debe mostrar las dos formas o ventanas) para tener en la pantalla
de diseno la segunda ventana, cargarle con sus propios label's, textbox's y buttons, es decir
contruirle su programa, recordar tambien asignarles sus propios NAME'S.

d) El codigo del BUTTON1 de la primera ventana Form1 es:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click
Form2.Show()
End Sub

Solo usar propiedad SHOW() con la ventana2 o FORM2

Recordar que si se quiere que FORM1 haga otro proceso u operación solo agregarle
componentes y mas BUTTON's

El Código del botón OK de la segunda ventana Form2, es:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click
Me.Close()
End Sub

Estamos viendo ahora un nuevo operador de visual basic NET, el operador ME, este
operador es una referencia o enlace directo al objeto activo, el evento button1_Clic() está
contenido dentro de esta FORM2 por tanto el objeto activo es FORM2 Me.Close() sería
equivalente a FORM2.CLOSE() pero visual basic prefiere trabajar mejor con referencias o
enlaces a objetos, por eso es mejor usar THIS.

Corrida: form1
Nota:
Recordar que si se quiere que FORM2 haga
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 111
otro proceso u operación solo agregarle
componentes y mas BUTTON's
Recordar que les indique que windowsforms tiene muchos y valiosos controles o
componentes en esta ventana se uso CALENDAR y se ve elegante

Corrida form2:

Recordar otra vez que


windowsforms tiene muchos y
valiosos controles o
componentes en esta ventana se
uso WEBBROWSER y se ve
elegante

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 112


4.- Estructuras, ciclos, decisiones, en Visual Basic
4.1.-Instrucciones condicionales Visual Basic
Instrucciones de control de programa que permiten alterar la secuencia normal de ejecución
de un programa. Estas instrucciones se dividen en tres grandes categorías:

1.- Instrucciones Condicionales que en VISUAL BASIC NET se implementan con las
instrucciones if y select case.

Instrucciones de ciclos con

 for
 do while loop
 do loop while
 Muchas de ellas con sus correspondientes componentes visuales, tanto en html como
en activex, htmlcontrols y webcontrols, pero para propósito del curso solo se usaran
los Controls ASP NET

Una de las más poderosas caracteristicas de cualquier computador es la capacidad que tiene
de tomar decisiones.

Es decir al comparar dos alternativas diferentes el computador puede tomar una decision
basandose en la evaluacion que hace de alguna condicion. Ejemplo de instrucciones
condicionales:

si sueldo > 3000


desplegar rico
si no
desplegar pobre
Fin-si
si sexo = 'm'
imprime mujer
si no
imprime hombre
Fin-si

De los ejemplos observar que los caminos a seguir por el computador dependeran de la
evaluacion que el computador hace con la condicion. Todo lenguaje de programacion debe
tener instrucciones que permitan formar condiciones e instrucciones que pueden evaluar esas
condiciones.

Pero recordar que lenguajes modernos y orientados a clientes-servidores de igual forma


tienen componentes que permiten del mismo modo al usuario tomar decisiones incluso
directamente en pantalla, es decir tambien existen los objetos, controles o componentes de
seleccion y decision en html, htmlcontontrols, activex, webcontrols.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 113


El formato general de una instruccion condicional es:

Como se observa, son cuatro partes bien diferenciadas entre si;

 La propia instruccion condicional en si


 La condicion
 El grupo cierto de instrucciones
 El grupo falso de instrucciones

Cuando el computador evalua una condicion el resultado de esa evaluacion solo es evaluado
de dos maneras o la condicion es CIERTA o la condicion es FALSA.

Esto dependerá del valor que tenga asignado o que se haya capturado para la variable que
está en la condició

Por ejemplo si se capturo 8000 en sueldo en el ejemplo a) entonces el computador indicaría


que la condicion es CIERTA pero en otro caso si a la variable sueldo primero se le asigno un
valor de 250 entonces el computador indicaría que la condicion es FALSA. Dependiendo del
resultado de la evaluacion, el programa realiza las instrucciones contenidas en el grupo de
cierto o falso respectivamente.

Empezaremos el análisis por la CONDICION presentada.

CONDICIONES SIMPLES VISUAL BASIC En general todas las condiciones se forman


con tres elementos los cuales son:

Variables Operadores relacionales Constantes o variables


sexo = “m”
sueldo > 30000
Carrera = “informatica”

Una condicion simple en visual basic NET se define como el conjunto de variables y/o
constantes unidas por los llamados operadores relacionales.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 114


4.2- OPERADORES RELACIONALES EN VISUAL BASIC

Los operadores relacionales que reconoce Visual Basic NET se presentan en la siguiente
tabla:

Operador Significado Descripcion


= Igual Es verdadero si las expresiones comparadas son
iguales
< Menor que Es verdadero si la expresión de la izquierda es
menor que la expresión de la derecha
> Mayor que Es verdadero si la expresión de la izquierda es
mayor que la expresión de la derecha
<> Diferente que Es verdadero si la expresión de la izquierda es
diferente de la expresión de la derecha
<= Menor o igual que Es verdadero si la expresión de la izquierda es
menoro igual que la expresión de la derecha
>= Mayor o igual que Es verdadero si la expresión de la izquierda es
mayor o igual que la expresión de la derecha

4.3.- INSTRUCCION IF… Then Else en VISUAL BASIC

Es la instrucción condicional más usada en los diversos lenguajes de programación, su


formato completo y de trabajo en VISUAL BASIC es:

If condicion Then
Instrucciones cuando la condicion sea cierta
Else
Instrucciones cuando la condicion sea falsa
End If

Si un if no ocupa un grupo falso de instrucciones entonces no usar la clausula else

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click
If SUELDO.Text > 3000 Then
MessageBox.Show("RICO")
Else
MessageBox.Show("POBRE")
End If
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 115


Si lo corremos veremos algo asi:

En Visual Basic NET es valido usar mas de


una instruccion dentro del grupo cierto o
falso del if.

Actividades de reforzamiento de lo aprendido

EJERCICIOS DE PROGRAMACION EN VISUAL BASIC NET

1.- Capturar un número cualesquiera e informar si es o no es mayor de 100

2.- Capturar un número entero cualesquiera e informar si es o no es multiplo de 4 (recordar


el operador mod analizado en el tema de operadores aritmeticos).

3.- Capturar los cinco datos más importantes de un Empleado, incluyendo el sueldo diario y
los dias trabajados desplegarle su cheque semanal solo si gano mas de $500.00 en la
semana, en caso contrario desplegarle un bono de despensa semanal de $150.00, PUEDEN
USAR PANELS PARA SEPARAR O MEJOR AUN OTRAS VENTANAS O FORMAS.

4.- Capturar los datos mas importantes de un estudiante incluyendo tres calificaciones
construir una boleta de calificaciones en un PANEL O VENTANA de respuesta bien bonita si
el estudiante es de la carrera de medicina, en caso contrario construir un PANEL O VENTANA
mas bonita todavia que despliega un oficio citando a los padres del estudiante a una platica
amistosa con los maestros de la escuela.

5.- Capturar los datos más importantes de un producto cualesquiera, incluyendo cantidad,
precio, etc. desplegar una orden de compra, solo si el producto es de origen nacional, en
caso contrario no hacer nada.

Nota: Es muy importante realizar siempre un diseño visual de lo que queremos


realizar en el grograma y como esto se vera en la aplicación, Visual Basic NET
facilita mucho esta situacion

4.4.- CONDICIONES COMPUESTAS EN VISUAL BASIC

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 116


En muchas ocasiones es necesario presentar más de una condicion para su evaluacion al
computador. Por ejemplo se necesita un programa que el computador muestre la boleta de un
alumno si este estudia la carrera de medicina y su promedio de calificaciones es mayor de
70.

Una condicion compuesta se define como dos o más condiciones simples unidas por los
llamados operadores lógicos.

Los operadores logicos que VISUAL BASIC NET reconoce son:

OPERADOR DESCRIPCION
AND Es verdadera si las dos expresiones comparadas son verdadera
OR Es verdadera si una de las dos expresiones es verdadera
NOT Invierte el valor de la expresión. Dos negaciones es una afirmación y
negar una afirmación es el valor contrario de la afirmacion
Xor Es verdadera si una de las dos expresiones comparadas es verdadera
AndAlso Es verdadera si las dos expresiones comparadas son verdadera, con al
particularidad de que evalua la segunda parte de la expresión si la
primera la cumple
OrElse Es verdadera si una de las dos expresiones comparadas son verdadera,
con al particularidad de que si cumple la primera expresión no continua
la siguientedando como verdadera la comparación logica

La cantidad total de casos posibles cuando se unen dos o mas condiciones simples esta dada
por la relacion 2n donde n es la cantidad de condiciones, la primera mitad de ellos empieza
en cierto y la segunda mitad en falso. Ejemplo, si formamos una condicion compuesta con
dos condiciones simples y el operador logico “y”, la cantidad total de casos posibles serian
22 = 4, y se puede construir la siguiente tabla de verdad.

Tabla de verdad con “AND”

PRIMERA CONDICION SEGUNDA CONDICION EVALUACION


SIMPLE SIMPLE
C C C
C F F
F C F
F F F

La evaluacion final, se obtiene usando la regla anteriormente descrita para una condicion
compuesta, que contiene el operador “AND”.

Esta tabla significa lo siguiente:

1.- Cualquiera que sean la cantidad de datos procesados, siempre caera en uno de estos cuatro
casos generales. La tabla de verdad para una condicion compuesta con “OR” es la siguiente:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 117


PRIMERA CONDICION SEGUNDA CONDICION EVALUACION
SIMPLE SIMPLE
C C C
C F C
F C C
F F F

Otro ejemplo: Construir una tabla de verdad para una condicion compuesta de tres o mas
condiciones simples es tambien tarea sencilla, solo recordar que;

1.- La cantidad posible de casos es 23 = 8 casos posibles, la mitad empiezan con Cierto y la
otra mitad empiezan con Falso.

2.- Para evaluar esta condicion triple primero se evaluan las dos primeras incluyendo su
operador bajo las reglas ya descritas y luego se evalua el resultado parcial contra la ultima
condicion y ultimo operador para obtener la evaluacion final.

Ejemplo una condicion compuesta de tres condiciones simples, donde el primer operador
logico es el “AND” y el segundo operador logico es el “OR”, daria la siguiente tabla de
verdad.

PRIMERA SEGUNDA EVALUACION TERCERA EVALUACION


CONDICION CONDICION DE PRIMERA CONDICION OR DE
SIMPLE SIMPLE Y SEGUNDA SIMPLE TERCERA Y
CONDICION CUARTA COL.
C C C C C
C C C F C
C F F C C
C F F F F
F C F C C
F C F F F
F F F C C
F F F F F

Programa ejemplo: Determinar de acuerdo a la edad si los datos del ususario son de un joven
o de una persona “anciana”, (edad limite = 30)

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click

If EDAD.Text < 30 And SEXO.Text = "H" Then


Label3.Text = "Muchacho Joven"

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 118


Else
Label3.Text = "Anciano"
End If
End Sub

Salida del programa

Actividades de reforzamiento de lo aprendido

EJERCICIOS DE PROGRAMACION

1.- Construir un programa que capture un número cualesquiera e informe si es o no es mayor


de 50 y múltiplo de tres. (Solo escribir el mensaje de respuesta de manera muy clara y esto
resuelve el problema)

2.- Construir un programa que indique si un número es un par positivo.

3.- Capturar los datos de un producto incluyendo su cantidad en existencia, desplegar una
orden de compra si la cantidad en existencia del producto es menor que el punto de reorden,
o si el origen del producto es nacional.

4.- Construir un programa que capture los datos de un empleado, desplegar en un panel o
ventana su cheque semanal si gana mas de $500.00 y si esta en el departamento de producción
en caso contrario desplegarle en otro panel o ventana un bono de despensa del 25% de su
sueldo semanal.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 119


4.5.-Instrucciones de control en visual basic.
INSTRUCCION SELECT CASE VISUAL BASIC

También existen ocasiones o programas donde se exige evaluar muchas condiciones a la vez,
en estos casos o se usa una condicion compuesta muy grande o se debe intentar convertir el
problema a uno que se pueda resolver usando la instrucción SELECT CASE.

Esta instrucción es una instrucción de


Select Case variableopcion decisión múltiple donde el compilador
case const1 prueba o busca el valor contenido en una
instruccion(es) variable ENTERA, CHARACTER,
case const2 STRING contra una lista de constantes
instruccion(es) apropiadas, cuando el computador
case const3 encuentra el valor de igualdad entre
Instruccion(es) variable y constante entonces ejecuta el
… grupo de instrucciones asociados a dicha
case Else instruccion(es) constante, si no encuentra el valor de
End Select igualdad entre variable y constante,
entonces ejecuta un grupo de
instrucciones asociados a un default,
aunque este ultimo es opcional. El
formato de esta instrucción es el
siguiente:

Programa ejemplo :

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click

Select Case LETRA.TEXT


Case "A"
ANIMALITO.TEXT = "AGUILA"
Case "B", "b"
ANIMALITO.TEXT = "BESTIA"
Case "C"
Dim ALFA As Integer
ALFA = 100 + 5
' observar como se encadenan strings usando simbolo &
ANIMALITO.TEXT = ALFA & " CABALLOS"
Case Else
ANIMALITO.TEXT = "NO HAY"
End Select

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 120


End Sub

Observar el caso “b”, se pueden usar más de


dos constantes.

En el caso “C” recordar que cada CASE


puede llevar un conjunto de instrucciones
que se ejecutaran hasta que el compilador
encuentre el siguiente case.

Observar y recordar en caso “C” como se


unen dos o mas strings, usando el signo &.

4.6.-Ciclo FOR TO NEXT


Instrucciones para ciclos resuelven el problema de repetir todo el programa o cierta parte del
programa más de una vez. Este ciclo es uno de los más usados para repetir una secuencia
de instrucciones sobre todo cuando se conoce la cantidad exacta de veces que se quiere que
se ejecute una instruccion simple o compuesta. El formato es el siguiente:

FOR VARCICLO = VALINICIAL TO VALFINAL [STEP INCR O DECR]


INSTRUCCION(ES)
NEXT

Ejemplo:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click

Dim X As Integer
LISTA.Items.Clear()
For X = 1 To 10
LISTA.Items.Add(X & "= MAMA")
Next X
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 121


Notas:

Se esta usando un objeto listbox con


NAME = LISTA para procesar el
conjunto de datos. O se usan
muchos webcontrols label o textbox
para desplegar todo lo que despliega
el ciclo for o se esta usando mejor
un objeto listbox para procesar el
. conjunto de datos. Se esta usando la
propiedad add de la coleccion
items del control listbox (lista).
Observar que para encadenar strings
en visual basic se usa el signo &

El metodo items.clear, es porque


cuando el usuario usa el click más
de una vez, el control listbox los va
agregando de nuevo abajo, por eso
en cuanto se activa el onclick lo
primero que se realiza es limpiar el
listbox.
El ciclo for es muy sencillo y no ocupa mucha explicacion, solo
empieza en UNO y se va incrementando de UNO en UNO

Casos Particulares del ciclo for:


1.- El ciclo comienza en uno y se incrementa de uno en uno, este es el caso más general.
2.- Pero el valor inicial puede se diferente de uno, ejemplo;

FOR X=5 TO 28
Desplegar X
NEXT

3.- Incluso el valor inicial puede ser negativo, ejemplo;

FOR X= -5 TO 18
Desplegar X
NEXT

4.- Los incrementos tambien pueden ser diferentes al de uno en uno, ej.;

FOR X=1 TO 50 STEP 4


Desplegar X
NEXT

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 122


5.- Incluso pueden ser decrementos, solo que en este caso, recordar;

5.1.- el valor inicial de la variable debe ser mayor que el valor final y usar un step negativo.

FOR X=100 TO 20 STEP - 5


Desplegar X
NEXT

El uso, gestión y manipulación de matrices (Que estudiaremos adelante) utilizan el bucle :

For … Each
Instrucciones…
Next

Veamos este ejemplo:

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button2.Click

Dim MiArreglo() As String = {“Uno”,”Dos”,”Tres”}


Dim SCadena As String
Dim Smensaje As String = “ ”
For Each SCadena In MiArreglo
Smensaje += SCadena & “ “
Next
MessageBox.Show(Smensaje.trim)
End Sub

Actividades de reforzamiento de lo aprendido

EJERCICIOS DE PROGRAMACION

1.- Construir un programa que despliegue los numeros del 20 al 30.

2.- Desplegar los enteros entre 50 y 30 acompañados de su potencia cuadrada y raiz cubica
respectiva (revisar tema de operadores aritmeticos y buscar la libreria de funciones
matematicas de Visual Basic).

3.- Desplegar los multiplos de 5, entre 10 y 50, acompañados de su factorial y logaritmo


respectivo (La misma recomendacion del ejercio anterior).

4.- Desplegar la tabla de multiplicar que el usuario indique

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 123


5.- Evaluar la funcion y = 5x2 + 3x + 8 cuando x= -3…10 (rango de -3 hasta 10)

4.5.-Ciclo DO WHILE LOOP

En este ciclo el cuerpo de instrucciones se ejecuta mientras una condicion permanezca


como verdadera en el momento en que la condicion se convierte en falsa el ciclo termina.
Su formato general es :

DO WHILE CONDICION(ES)
INSTRUCCION(ES) CIERTAS
INSTRUCCION(ES) DE SALIDA DE CICLO
LOOP
Programa

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click

Dim X As Integer
X=1
LISTA.Items.Clear()

Do While X <= 10
LISTA.Items.Add(X & "= GATO")
X=X+1
Loop
End Sub

Corrida

Nota:

While puede llevar dos condiciones; en este caso


inicializar 2 variables de condicion y cuidar que
existan 2 de rompimiento o terminacion de ciclo.

El grupo cierto de instrucciones puede ser una sola


instruccion o todo un grupo de instrucciones. La
condicion puede ser simple o compuesta.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 124


A este ciclo tambien se le conoce tambien como ciclo de condicion de entrada o prueba por
arriba porque este ciclo evalua primero la condicion y posteriormente ejecuta las
instrucciones.

Actividades de reforzamiento de lo aprendido

EJERCICIOS DE PROGRAMACION

1.- Desplegar enteros entre 50 y 80

2.- Desplegar multiplos de 4 entre 60 y 20 acompanados de su logaritmos de base 10 y base


e respectivos (revisar tema operadores atitmeticos)

3.- Construir la tabla de dividir que el usuario indique

4.- Evaluar una función cualesquiera para el rango de valores de x de -3 a +5

4.7.-Ciclo DO LOOP WHILE

Su diferencia básica con el ciclo do while loop es que la prueba de condición es hecha al
finalizar el ciclo, es decir las instrucciones se ejecutan cuando menos una vez porque primero
ejecuta las instrucciones y al final evalúa la condición.

También se le conoce por esta razón como ciclo de condición de salida.

Su formato general es:

DO
INSTRUCCION (ES) CIERTAS
INSTRUCCION (ES) DE SALIDA DE CICLO
LOOP WHILE CONDICION (ES)

Programa

Private Sub EVENTO1(ByVal sender As Object, ByVal e As System.EventArgs)


Dim X As Integer
X=1

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 125


LISTA.Items.Clear()
Do
LISTA.Items.Add(X & " perico")
X=X+1
Loop While X <= 10
End Sub

Otra diferencia básica con el ciclo do while loop es que aunque la condición sea falsa desde
un principio el cuerpo de instrucciones se ejecutara por lo menos una vez.

CONCLUSIONES CICLOS VISUAL BASIC

En Visual Basic NET dado un problema o programa cualesquiera que sea el tipo de ciclo que
se utilice, se resuelve con:

1. Si se conoce la cantidad exacta de veces que se quiere que se ejecute el ciclo o si el


programa de alguna manera puede calcularla usar for..net.
2. Si se desconoce la cantidad de veces a repetir el ciclo o se quiere mayor control sobre
la salida o terminacion del mismo entonces usar do while loop.
3. Si se quiere que al menos una vez se ejecute el ciclo entonces usar do loop while.

4.7.-Arreglos en Visual Basic NET

Aspectos básicos
También conocido con las denominaciones de matriz y vector, un array es aquel elemento
del lenguaje que nos permite agrupar un conjunto de valores del mismo tipo, y acceder
a ellos a través de una misma variable o identificador, especificando la posición o
índice en donde se encuentra el dato a recuperar. El Código fuente , muestra las
operaciones esenciales que podemos realizar con un array.

Private sub form1_load…


‘ vamos a utilizar un control textbox con la propiedad multiliea a verdadero
‘ para visualizar los resultados de los programas, y botones para cada
‘caso de estudio..
' declarar un array de tipo String, el número de elementos es el indicado
' en la declaración más uno, porque la primera posición de un array es cero
Dim sNombres(3) As String
' asignar valores al array
sNombres(0) = "Ana"
sNombres(1) = "Pedro"
sNombres(2) = "Antonio"
sNombres(3) = "Laura"
' pasar un valor del array a una variable
Dim sValor As String
sValor = sNombres(2)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 126


' mostrar en la pantalla el valor pasado a una variable
' y un valor directamente desde el array
TextBox1.Text =TextBox1.Text &"Valor de la variables: " & sValor & VbCrLf
TextBox1.Text =TextBox1.Text & "Valor del array, posición 1: "& sNombres(1)
End Sub

A lo largo de este texto, emplearemos de forma genérica el término array, para


referirnos a este elemento del lenguaje. Por otra parte, recomendamos al lector la creación
de un nuevo proyecto en el IDE de tipo consola, para realizar las pruebas mostradas a lo
largo del tema.

La clase Array
Esta clase, perteneciente a la jerarquía de clases del sistema, es decir, incluida en el
espacio de nombres System, proporciona a través de sus miembros, acceso orientado a
objeto para los arrays que manipulemos en nuestras aplicaciones. Esto quiere decir que
los arrays, como sucede con otros elementos del lenguaje, son también objetos.

Al igual que el resto de elementos del entorno, los arrays son tipos pertenecientes al sistema
común de tipos de la plataforma o CTS, y se encuentran clasificados como tipos por
referencia; esto quiere decir, que durante la ejecución, un array será gestionado en la zona
de memoria conocida como montón o heap.
Aunque podemos trabajar con los arrays como objetos, no será necesario instanciar un
objeto de esta clase para poder disponer de un array. Al declarar una variable como array,
implícitamente se instancia un objeto de la clase. En sucesivos apartados de este tema,
haremos una descripción de los miembros de instancia y compartidos más importantes de la
clase Array.

Adecuación de los arrays en VB con los arrays de la plataforma .NET

Los arrays son uno de los elementos de VB que menos han evolucionado a lo largo de
las sucesivas versiones aparecidas de este lenguaje. Todo esto, sin embargo, ha
cambiado con la llegada de la plataforma .NET.
La especificación CLS del entorno .NET, dicta que todos los lenguajes que cumplan
con la misma, podrán ser utilizados bajo .NET Framework. Esto quiere decir además, que
dos ensamblados escritos en distintos lenguajes de la plataforma, podrán compartir código
entre ellos. En el caso que nos ocupa, una aplicación VB.NET podrá llamar a un método
de un objeto escrito en C# que devuelva un array, y dicho array, será manejado desde
VB.NET.
Los diseñadores de .NET han realizado un gran esfuerzo en proporcionar la máxima
optimización y versatilidad a los arrays, siempre y cuando, el lenguaje del entorno que
los utilice, cumpla con unos mínimos requerimientos. En este aspecto, VB.NET como
lenguaje, ha obtenido toda la potencia de base inherente en el sistema para la creación

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 127


y manipulación de arrays; mientras que como contrapartida, ciertas características
exclusivas en VB para el manejo de arrays han necesitado ser readaptadas. Algunas de
estas características se describen a continuación.

El primer índice de un array debe ser siempre cero


VB.NET no soporta la instrucción Option Base, que nos permitía indicar que el primer
índice de un array podía ser cero o uno. Por lo tanto, al declarar ahora un array en
VB.NET, su número de elementos será el indicado en la declaración más uno. Veamos
las diferencias en el Código fuente:

Private sub form1_load…


' array de 3 elementos
Dim sNombres(2) As String
sNombres(0) = "Pedro"
sNombres(1) = "Ana"
sNombres(2) = "Jaime"
End Sub

Todos los arrays son dinámicos

En VB.NET todos los arrays son de tamaño variable, tanto si se especifica como no un
tamaño al ser declarados. En este punto debemos matizar un aspecto: cada vez que en
VB.NET se cambia el tamaño de un array, el entorno internamente destruye el array actual,
y crea un nuevo objeto de la clase Array, con el nuevo tamaño especificado, usando el
mismo nombre de la variable correspondiente al array eliminado en primer lugar.

Declaración
Declararemos un array de igual forma que hacemos con una variable normal, con la
excepción de que junto al nombre de la variable, situaremos unos paréntesis. Esto indica
que dicha variable contiene un array. Opcionalmente, podemos especificar entre los
paréntesis las dimensiones del array, o número de elementos que va a contener. Es posible
también, realizar una asignación de valores al array en el mismo momento de su
declaración. El Código fuente, muestra algunos ejemplos.

Private sub form1_load…


' formas de declaración de arrays
' ===============================
' 1)
' estableciendo el número de elementos
Dim sNombres(2) As String

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 128


' 2)
' asignando valores al array al mismo tiempo que se declara, la lista de valores
' debe ir encerrada entre llaves
Dim sEstaciones() As String = {"Ana", "Pedro", "Luis"}
' 3)
' indicando el tipo de dato pero no el número de elementos, de este modo la variable
' todavía no es considerada un array ya que contiene una referencia a Nothing
Dim iValores() As Integer
' 4)
' indicando el tipo de dato y estableciendo una lista vacía de elementos, a diferencia
' del caso anterior, la variable ahora sí
' es considerada un array aunque de longitud cero
Dim iDatos() As Integer = {}
' 5)
' instanciando el tipo de dato, estableciendo el número de elementos al
' instanciar, e indicando que se trata de un array al situar las llaves
Dim iCantidades() As Integer = New Integer(20) {}
' 6)
' declarar primero la variable que contendrá el array, asignar valores al array
' al mismo tiempo que se instancia la lista de valores debe ir encerrada
' entre llaves
Dim iNumeros() As Integer
iNumeros = New Integer() {10, 20, 30, 10, 50, 60, 10, 70, 80}
End Sub

Recomendamos al lector, que en estos ejemplos con arrays, utilice el depurador para
ejecutar línea a línea el código, y abra la ventana Locales del depurador para ver en
cada caso, el contenido de los elementos del array.

Asignación y obtención de valores


Para asignar u obtener valores de los elementos de un array, emplearemos la variable que
contiene el array haciendo referencia al índice o posición a manipular. O bien, puesto que
un array es un objeto, utilizaremos los métodos SetValue( ) y GetValue( ) que asignan
y obtienen respectivamente los valores del array. Veamos un ejemplo en el Código fuente
:
Private sub button1…..
' asignación de valores a los elementos de un array
' =================================================
Dim sNombres(4) As String
' directamente sobre la variable, haciendo referencia al índice

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 129


sNombres(0) = "Juan"
sNombres(1) = "Ana"
sNombres(2) = "Luis"
' o con el método SetValue(), asignando el valor en el primer parámetro
' y especificando la posición en el segundo
sNombres.SetValue("Elena", 3)
sNombres.SetValue("Miguel", 4)
' obtención de valores de un array
Dim sValorA As String
Dim sValorB As String
sValorA = sNombres(2) ' directamente de la variable
sValorB = sNombres.GetValue(3) ' usando el meth GetValue
TextBox1.Text = "Contenido de las variables " & vbCrLf
TextBox1.Text = TextBox1.Text & "==========================" & vbCrLf
TextBox1.Text = TextBox1.Text & "ValorA ValorB:" & vbCrLf
TextBox1.Text = TextBox1.Text & sValorA & vbTab & sValorB & vbCrLf
End Sub

Recorrer el contenido
Para realizar un recorrido por los elementos de un array, disponemos de las funciones
LBound( ) y UBound( ), que devuelven el número de índice inferior y superior
respectivamente del array que pasemos como parámetro. No obstante, la orientación a
objetos proporcionada por el entorno, pone a nuestra disposición el nuevo conjunto de
características que comentamos seguidamente.
Length. Esta propiedad de un objeto array devuelve el número de elementos que
contiene.

GetLowerBound( ), GetUpperBound( ). Estos métodos de un objeto array,


devuelven respectivamente, el número de índice inferior y superior de una
dimensión del array. El resultado es el mismo que usando LBound( ) y
UBound( ), pero desde una perspectiva orientada a objetos.
Enumeradores. Un objeto enumerador pertenece al interfaz IEnumerator,
diseñado para realizar un recorrido o iteración a través de uno de los diferentes
tipos de colección (arrays incluidos) existentes en .NET Framework. Mediante el
método GetEnumerator( ) de un objeto array, obtenemos un objeto que implementa
el interfaz Ienumerator, que sólo puede realizar labores de lectura sobre el array,
en ningún caso de modificación.

La estructura de control utilizada para recorrer el array, puede ser indistintamente un bucle
For...Next, For Each...Next, o la novedosa técnica de los objetos enumeradores

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 130


proporcionados por el objeto array. Como muestra de estas funcionalidades, el Código
fuente siguiente que vemos a continuación, contiene algunos ejemplos de cómo realizar una
iteración sobre los elementos de un array.

Private Sub Button1.Click…..


' recorrer un array
Dim sNombres() As String = {"Ana", "Pedro", "Pablo", "Jorge", "Jesus"}
Dim iContador As Integer
Dim sUnNombre As String
' modo tradicional
TextBox1.Text = TextBox1.Text & "Recorrido del array con LBound() y UBound()"
& vbCrLf
For iContador = LBound(sNombres) To UBound(sNombres)
TextBox1.Text = TextBox1.Text & "Posicion " & vbTab & iContador & vbTab & _
sNombres(iContador) & vbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf ' linea en blanco con bucle For Each
TextBox1.Text = TextBox1.Text & "Recorrido del array con bucle For Each" &
vbCrLf
For Each sUnNombre In sNombres
TextBox1.Text = TextBox1.Text & "Nombre actual: " & sUnNombre _
& vbCrLf
Next
' linea en blanco usando la propiedad Length

TextBox1.Text = TextBox1.Text & vbCrLf


TextBox1.Text = TextBox1.Text & "Recorrido del array con propiedad Length" &
vbCrLf
For iContador = 0 To (sNombres.Length - 1)
TextBox1.Text = TextBox1.Text & "Posicion: " & vbTab & " Valor" _
& iContador & vbTab & sNombres(iContador) & vbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf ' linea en blanco
' usando los métodos GetLowerBound() y GetUpperBound()
TextBox1.Text = TextBox1.Text & "Recorrido del array con métodos
GetLowerBound() y GetUpperBound()" & vbCrLf
For iContador = sNombres.GetLowerBound(0) To sNombres.GetUpperBound(0)
TextBox1.Text = TextBox1.Text & "Posicion: " & iContador & vbTab & " Valor: " _
& sNombres(iContador) & vbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf ' linea en blanco

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 131


' recorrer con un enumerador
TextBox1.Text = TextBox1.Text & "Recorrido del array con un enumerador" &
vbCrLf
Dim sLetras() As String = {"a", "b", "c", "d", "e", "f"}
Dim oEnumerador As System.Collections.IEnumerator
' obtener el enumerador del array
oEnumerador = sLetras.GetEnumerator()
' con un enumerador no es necesario posicionarse en el primer elemento ni
' calcular la cantidad de elementos del array, sólo hemos de avanzar posiciones con
' MoveNext() y obtener el valor actual con Current
While oEnumerador.MoveNext()
TextBox1.Text = TextBox1.Text & "Valor actual: " & oEnumerador.Current &
vbCrLf
End While
End Sub

Modificación de tamaño
Para aumentar o disminuir el número de elementos de un array disponemos de la
palabra clave ReDim. Esta instrucción crea internamente un nuevo array, por lo que los
valores del array original se pierden. Evitaremos este problema utilizando junto a ReDim
la palabra clave Preserve, que copia en el nuevo array, los valores del array previo.
Veamos unos ejemplos en el Código fuente:

Private Sub Button1.Click…


' modificar el tamaño de un array
' ===============================
Dim sNombres(2) As String
sNombres(0) = "Juan"
sNombres(1) = "Pedro"
sNombres(2) = "Elena"
TextBox1.Text = TextBox1.Text & "Array sNombres original" & VbCrLf
MostrarArray(sNombres)
' ampliamos el número de elementos ,pero perdemos el contenido previo
ReDim sNombres(4)
sNombres(3) = "Isabel"
sNombres(4) = "Raquel"
TextBox1.Text = TextBox1.Text & "Array sNombres con tamaño ampliado"
&VbCrLf
MostrarArray(sNombres)
' creamos otro array

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 132


Dim sMasNombres(2) As String
sMasNombres(0) = "Juan"
sMasNombres(1) = "Pedro"
sMasNombres(2) = "Miguel"
TextBox1.Text = TextBox1.Text & "Array sMasNombres original" & VbCrLf
MostrarArray(sMasNombres)
' ampliamos el array sin perder elementos
ReDim Preserve sMasNombres(4)
sMasNombres(3) = "Antonio"
sMasNombres(4) = "Paco"
TextBox1.Text ="Array sMasNombres ampliado sin perder valores" & VbCrLf
MostrarArray(sMasNombres)
' reducimos el array, pero sin perder los primeros elementos
ReDim Preserve sMasNombres(1)
TextBox1.Text = TextBox1.Text & "Array sMasNombres reducido" & VbCrLf
MostrarArray(sMasNombres)
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

Private Sub MostrarArray(ByVal sMiLista() As String)


' este es un procedimiento de apoyo que muestra el array pasado como parámetro
Dim iContador As Integer
For iContador = 0 To sMiLista.Length - 1
TextBox1.Text = TextBox1.Text &"Elemento: “ & VbTab & ” Valor: " _
& iContador & VbTab & sMiLista(iContador) &VbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

Uso del método CreateInstance() para establecer el número de elementos


en un array
Ya hemos comprobado que al crear un array en VB.NET, el primer índice es siempre cero,
y además, el número de elementos del array es el indicado en la declaración más uno.
Sin embargo, la clase Array dispone del método compartido CreateInstance( ), que como
su nombre indica, permite crear una nueva instancia de la clase, es decir un objeto array,
con la particularidad de que en este caso, el número de elementos del array será realmente
el que establezcamos al llamar a este método.

El Código fuente siguiente, muestra la diferencia entre crear un array del modo habitual,
y empleando CreateInstance( ).

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 133


Private Sub Form1.Load…
' declarar un array del modo habitual:
' este array tiene cuatro elementos, desde el índice 0 al 3
Dim sEstaciones(3) As String
sEstaciones(0) = "Primavera"
sEstaciones(1) = "Verano"
sEstaciones(2) = "Otoño"
sEstaciones(3) = "Invierno"
TextBox1.Text = TextBox1.Text & "Array sEstaciones" &VbCrLf
MostrarArray(sEstaciones)
TextBox1.Text = TextBox1.Text & vbCrLf

' crear un array instanciándolo con el método CreateInstance()


' de la clase Array
Dim sColores As Array
' este array tendrá tres elementos reales que van desde el índice 0 hasta el 2
sColores = Array.CreateInstance(GetType(String), 3)
sColores(0) = "Azul"
sColores(1) = "Rojo"
sColores(2) = "Verde"
TextBox1.Text = TextBox1.Text & "Array sColores" & VbCrLf
MostrarArray(sColores)
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

Private Sub MostrarArray(ByVal sMiLista() As String)


' muestra el array pasado como parámetro
Dim iContador As Integer
For iContador = 0 To sMiLista.Length - 1
TextBox1.Text = TextBox1.Text &"Elemento: “ & VbTab & ” Valor: " _
& iContador & VbTab & sMiLista(iContador) & VbCrLf
Next
End Sub

Paso de arrays como parámetros, y devolución desde funciones


Podemos pasar un array como parámetro a una rutina de código, teniendo en cuenta que
los cambios que realicemos sobre el array en el procedimiento llamado, se mantendrán
al volver el flujo de la ejecución al procedimiento llamador.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 134


Ello es debido a que los arrays son tipos por referencia del entorno, y por lo tanto, las
variables del array que manejamos tanto desde el procedimiento llamador, como desde
el procedimiento llamado, son en realidad punteros hacia una misma zona de memoria o
referencia, la que contiene el array.

En el ejemplo del siguiente Código fuente, comprobaremos que al pasar un array por valor,
los cambios que realicemos sobre sus elementos se mantendrán al volver al procedimiento
que hizo la llamada.

Private Sub button1.Click…


TextBox1.Text = “”
Dim iValores() As Integer = {10, 20, 30}
' en ambos casos, se pasa una referencia del array
ManipArrayVal(iValores)
ManipArrayRef(iValores)
' al volver de las llamadas a los procedimientos, ' el array ha sido modificado en
' ambas llamadas, independientemente de que haya sido pasado por ' valor o
' referencia
MostrarArray(iValores)
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

' a este procedimiento le pasamos un array por valor


Private Sub ManipArrayVal(ByVal iListaPorValor As Integer())
' cambiar elemento del array
iListaPorValor(0) = 888
End Sub
' a este procedimiento le pasamos un array por referencia
Private Sub ManipArrayRef(ByRef iListaPorReferencia As Integer())
' cambiar elemento del array
iListaPorReferencia(2) = 457
End Sub
Private Sub MostrarArray(ByVal sMiLista() As Integer)
' muestra el array pasado como parámetro
Dim iContador As Integer
For iContador = 0 To sMiLista.Length – 1
TextBox1.Text = TextBox1.Text &"Elemento: “ & VbTab & ” Valor: " _
& iContador & VbTab & sMiLista(iContador) & VbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 135


End Sub

Clonación
Para evitar el problema planteado en el apartado anterior, si necesitamos disponer de un
array con las mismas características que uno ya existente, y que sea totalmente
independiente del primero, utilizaremos el método Clone( ). Con esto solucionaremos
el problema de que al pasar un array como parámetro, las modificaciones que precisemos
realizar, afecten al array original. Veamos un ejemplo en el Código fuente.

Private Sub Butto1.Click…


' crear un array
TextBox1.Text = “”
Dim iValores() As Integer = {10, 20, 30}
CambiaArray(iValores)
' mostrar el array original, ' en este no se habrán producido cambios
TextBox1.Text = TextBox1.Text & "Array original " & VbCrLf
MostrarArray4(iValores)
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Private Sub CambiaArray(ByVal iListaDatos As Integer())


' crear un array clónico, cambiarle valores y mostrarlo
Dim iListaClonada As Array
iListaClonada = iListaDatos.Clone()
iListaClonada(0) = 621
iListaClonada(1) = 900
TextBox1.Text = TextBox1.Text &"Array clónico" & VbCrLf
MostrarArray4(iListaClonada)
End Sub
Private Sub MostrarArray4(ByVal sMiLista() As Integer)
Dim iContador As Integer
For iContador = 0 To sMiLista.Length – 1
TextBox1.Text = TextBox1.Text &"Elemento: “ & iContador & VbTab _
& ” Valor: "& VbTab & sMiLista(iContador) & VbCrLf
Next
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Copia
Si intentamos copiar un array asignando la variable que contiene un array a otra, el resultado

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 136


real serán dos variables que apuntan a la misma lista de valores, por lo que en definitiva sólo
tendremos un array, al cual podremos acceder usando dos variables. Ello es debido a que
como explicamos en un apartado anterior, los arrays son tipos por referencia que apuntan al
mismo conjunto de valores.

Podemos clonar el array, como se ha descrito en el apartado anterior, con lo que


obtendremos un nuevo array, que será idéntico al original.

O bien, podemos copiar el array utilizando los métodos CopyTo( ) y Copy( ) de la clase
array. La diferencia con respecto a la clonación, consiste en que al copiar un array, el array
destino ya debe estar creado con el número suficiente de elementos, puesto que los
métodos de copia de la clase Array, lo que hacen es traspasar valores de los elementos
del array origen al array destino, en función de los parámetros utilizados, copiaremos
todos los elementos o un subconjunto. Veamos unos ejemplos en el Código fuente:

Private Sub Button1.Click….


Dim sColores(3) As String
TextBox1.Text = “”
sColores(0) = "Azul"
sColores(1) = "Verde"
sColores(2) = "Rosa"
sColores(3) = "Blanco"
MostrarArray5(sColores)

' copiar usando el método CopyTo(), copiamos en el array sColorDestino,


' y comenzando por su posición 2, los valores del array sColores
Dim sColorDestino(6) As String
sColores.CopyTo(sColorDestino, 2)
TextBox1.Text = TextBox1.Text & "Array sColorDestino de la posic 2 en adelante "
_
& VbCrLf
MostrarArray5(sColorDestino)
' copiar usando el método Copy(), copiamos en el array sListaColores,
' a partir de su posición 2, 2 elementos del array sColores, comenzando
' desde la posición 1 de sColores
Dim sListaColores(5) As String
Array.Copy(sColores, 1, sListaColores, 2, 2)
TextBox1.Text = TextBox1.Text & "Array sListaColores de la posic 2 se toman 2 " _
& vbCrLf
MostrarArray5(sListaColores)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 137


TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Private Sub MostrarArray5(ByVal sMiLista() As String)


Dim iContador As Integer
For iContador = 0 To sMiLista.Length - 1
TextBox1.Text = TextBox1.Text &"Elemento: “ & iContador & _
VbTab & ” Valor: " & VbTab & sMiLista(iContador) & VbCrLf
Next
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Inicialización de valores
Para inicializar o eliminar los valores de los elementos de un array, utilizaremos el
método Clear, al que pasaremos el array a inicializar, el índice a partir del que
comenzaremos, y el número de elementos. Los valores serán inicializados en función
del tipo de dato del array; cadena vacía en arrays String; cero en arrays numéricos, etc
Veamos el Código fuente:
Private Sub Button1.Click…
TextBox1.Text = “ “
' array String, asignar valores e inicializar
Dim sLetras(2) As String
sLetras(0) = "a"
sLetras(1) = "b"
sLetras(2) = "c"
' limpiar elementos en un array de tipo String,
' los elementos limpiados quedan como cadena vacía
Array.Clear(sLetras, 0, 1)
TextBox1.Text = TextBox1.Text & "Array sLetras" & VbCrLf
MostrarArray6(sLetras)
TextBox1.Text = TextBox1.Text & VbCrLf

' array Integer, asignar valores e inicializar


Dim iNumeros() As Integer = {100, 200, 300, 400, 500, 600}
' limpiar elementos en un array de tipo Integer, los elementos limpiados
' se ponen a 0
Array.Clear(iNumeros, 1, 2)
TextBox1.Text = TextBox1.Text & "Array iNumeros" & VbCrLf
MostrarArrayNum(iNumeros)
TextBox1.Text = TextBox1.Text & VbCrLf

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 138


' array Object, asignar valores e inicializar
Dim oVarios(6) As Object
oVarios(0) = "Hola"
oVarios(1) = 456
oVarios(2) = 1200
oVarios(3) = #12/25/2001#
oVarios(4) = 900
oVarios(5) = True
oVarios(6) = "adelante"
' al ser este un array de tipo Object los elementos limpiados se
' establecen a Nothing
Array.Clear(oVarios, 3, 2)
TextBox1.Text = TextBox1.Text & "Array oVarios" & VbCrLf
MostrarArrayObj(oVarios)
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

' recorrer un array de cadenas


Private Sub MostrarArray6(ByVal sMiLista() As String)
Dim iContador As Integer
For iContador = 0 To sMiLista.Length - 1
TextBox1.Text = TextBox1.Text &"Elemento: “ & iContador & VbTab & _
” Valor: " & VbTab & sMiLista(iContador) & VbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub
' recorrer un array de números
Private Sub MostrarArrayNum(ByVal iMiLista() As Integer)
Dim iContador As Integer
For iContador = 0 To iMiLista.Length - 1
TextBox1.Text = TextBox1.Text &"Elemento: “ & iContador & VbTab & ” _
Valor: " & VbTab & iMiLista(iContador) & VbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

' recorrer un array de objetos


Private Sub MostrarArrayObj(ByVal oMiLista() As Object)
Dim iContador As Integer

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 139


For iContador = 0 To oMiLista.Length - 1
TextBox1.Text = TextBox1.Text &"Elemento: “ & iContador & vbTab & ” _
Valor: " & vbTab & oMiLista(iContador) & vbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

Ordenación
Para ordenar un array disponemos del método Sort( ), que al estar sobrecargado,
tiene varias implementaciones; la más básica de ellas es la que ordena la totalidad del
array. También podemos ordenar una parte del array, indicando la posición inicial y
cantidad de elementos a ordenar, etc.
El método Reverse( ), invierte la posición de todos o parte de los elementos de un array. En
este punto, debemos matizar que no se realiza un orden inverso de los elementos,
sino que se cambian las posiciones de los mismos. Ver Código fuente :
Private Sub button1.Click….
TextBox1.Text = “ “
' ordenar todo el array
Dim sLetras1() As String = {"z", "a", "g", "m", "w", "i", "c", "b"}
TextBox1.Text = TextBox1.Text &"arreglo original" & VbCrLf
MostrarArray7(sLetras1)
Array.Sort(sLetras1)
TextBox1.Text = TextBox1.Text &"Ordenar todos el array" & VbCrLf
MostrarArray7(sLetras1)
' ordenar parte del array
Dim sLetras2() As String = {"z", "a", "g", "m", "w", "i", "c", "b"}
Array.Sort(sLetras2, 4, 3)
TextBox1.Text = TextBox1.Text & "Ordenar parte del array" & VbCrLf
MostrarArray(sLetras2)
' invertir valores dentro del array
Dim sLetras3() As String = {"z", "a", "g", "m", "w", "i", "c", "b"}
Array.Reverse(sLetras3, 2, 4)
TextBox1.Text = TextBox1.Text & "Invertir valores del array" & VbCrLf
MostrarArray7(sLetras3)
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub
Private Sub MostrarArray7(ByVal sMiLista() As String)
Dim iContador As Integer
For iContador = 0 To sMiLista.Length - 1
TextBox1.Text = TextBox1.Text &"Elemento: “ & iContador & VbTab & ” _

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 140


Valor: " & VbTab & sMiLista(iContador) & VbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

Búsqueda
Los métodos IndexOf( ) y LastIndexOf( ) de la clase Array, nos permiten buscar un
elemento en un array comenzando la búsqueda desde el principio o final respectivamente.
Ya que ambos disponen de diferentes implementaciones al estar sobrecargados, consulte el
lector la documentación de la plataforma. El Código fuente siguiente muestra algunos
ejemplos de uso.
Private Sub Button1.click…
TextBox1.Text = “ “
Dim sNombres() As String = {"Alberto", "Juan", "Ana", "Paco", "Miguel", "Ana"}
' buscar una cadena a partir del índice 0 del array
TextBox1.Text = TextBox1.Text & "Paco está en la posición “ & VbTab & _
Array.IndexOf(sNombres, "Paco") & VbCrLf
' buscar una cadena a partir del índice 3 del array
TextBox1.Text = TextBox1.Text & "Ana está en la posición" & _
" comenzando a buscar desde índice 3" & VbTab & _
Array.IndexOf(sNombres, "Ana", 3) & VbCrLf
' introducir un valor a buscar en el array, si no existe se devuelve -1
Dim iPosicionBuscar As Integer
Dim TNom As Integer
TNom = InputBox("Introducir nombre a buscar")
iPosicionBuscar = Array.IndexOf(sNombres, Tnom)
If iPosicionBuscar = -1 Then
MsgBox("El nombre no está en el array")
Else
MsgBox("El nombre está en la posición “ & VbTab &_
iPosicionBuscar & VbTab & “ del array " )
End If
' buscar comenzando por la última posición
Dim iNumeros() As Integer
Dim iUltPosicionBuscar As Integer
TextBox1.Text = TextBox1.Text & vbCrLf
iNumeros = New Integer() {10, 20, 30, 10, 50, 60, 10, 70, 80}
TextBox1.Text = TextBox1.Text & " En el arreglo {10, 20, 30, 10, 50, 60, 10, 70,
80}"_
& vbCrLf

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 141


TextBox1.Text = TextBox1.Text & "El 10 está en la posición " & _
Array.LastIndexOf(iNumeros, 10) & " comenzando por el final"
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

EJERCICIOS DE PROGRAMACION DE ARREGLOS TIPO ARREGLOS

1.- Capturar y desplegar 5 precios de productos cualesquiera usando dos panel uno para
capturar y uno para desplegar

2.- Capturar 4 sueldos en un panel desplegarlos aumentados en un 25% en otro panel

3.- Capturar los datos de 5 productos comprados en una tienda, incluyendo nombre, precio y
cantidad en sus 3 listas respectivas, despues calcular una cuarta lista con el gasto total por
cada producto desplegarlo todo en un segundo panel e incluir tambien el gran total

4.- Capturar en una lista solamente 6 numeros multiplos de 5, se debe de estar capture y
capture numeros hasta que se completen los 6 multiplos de 5

Arrays multidimensionales
Todos los arrays vistos hasta el momento han sido de tipo unidimensional, es decir,
estaban compuestos de una lista de valores única. .NET Framework nos provee también de
la capacidad de crear arrays formados por más de una lista de valores, o lo que es igual,
arrays multidimensionales. Un array de este tipo, se caracteriza por estar compuesto de
varias dimensiones o listas anidadas al estilo de filas y columnas. Si declaramos un array del
modo que muestra el Código fuente:
Dim iDatos(2, 4) As Integer
Crearíamos un array multidimensional formado por tres filas y cinco columnas. En
este caso, el número correspondiente a la primera dimensión denota las filas, mientras que
el número de la segunda dimensión hace lo propio para las columnas. La Figura muestra
un diagrama con la estructura de este array.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 142


Estructura de un array multidimensional.

En este tipo de arrays, para acceder a los valores, debemos especificar la dimensión y la
posición a la que vamos a asignar o recuperar un dato. Ver código.
Private Sub Form1.Load…
' crear array multidimensional y rellenar de valores
Dim iDatos(2, 4) As Integer

Los elementos de la tabla se deberan simbolizar con el nombre de la tabla y 2 subindices, el


primer subíndice referencia al renglón o fila y el siguiente subíndice referencia la columna
los dos dentro del mismo corchete.

La declaración de una tabla sera de acuerdo al siguiente formato:

shared dim nomtabla(reng-1,col-1) as <tipodato>

Ejemplo:

shared dim sueldo(3,4) as double

Recordar que va a generar una matriz que tendra cuatro renglones y cinco columnas
empieza en sueldo(0,0)

Para procesar (recordar solo operaciones y comparaciones) internamente todos los


elementos de la tabla se ocupan dos ciclos for uno externo para controlar renglón o fila y
uno interno para controlar columna.

Para capturar sus elementos, usaremos un textbox y un boton de captura, solo tener
cuidado o mucho control sobre los indices rEN y col como lo muestra el ejemplo.

Para efectuar otros procesos tales como operaciones, despliegues con todos los elementos
de la tabla se deberan usar 2 ciclos un for externo para controlar renglon y un for interno
para controlar columna.

Programa

' declarando lista global


' recordar que son 3 reng y 4 columnas
Shared CALIFICACION(2, 3) As Integer
' declarando reng y col como global
Dim R, C As Integer

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 143


Private Sub Button1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click

' En este modulo solo se trabaja con el arreglo en memoria


CALIFICACION(R, C) = CALIF.Text
C=C+1
CALIF.Text = ""
If C = 4 Then
R=R+1
C=0
End If
If R = 3 Then
CALIF.Visible = False
End If
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button2.Click
Dim TEMP As String
' procesando y regalando 50 puntos a todos
For R = 0 To 2
For C = 0 To 3
CALIFICACION(R, C) = CALIFICACION(R, C) + 50
Next C
Next R
' desplegando los datos
For R = 0 To 2
TEMP = CALIFICACION(R, 0) & " " & CALIFICACION(R, 1) & " " & CALIFICACION(R, 2) & " " &
CALIFICACION(R, 3)
LISTA1.Items.Add(TEMP)
' limpiando temporal antes de otro renglon
TEMP = " "
Next
End Sub

Notas: Observar el formato de declaracion y como se controlan los indices de captura r, c


Para procesar los elementos se usan dos ciclos for y el formato tabla (reng,col).

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 144


En este problema se usa el objeto LISTBOX para presentar el resultado mas adelante se
usara un objeto mas apropiado.

Diseño: Corrida:

Las matrices en Visual Basic tienen la capacidad de cambiar o modificar su tamaño, es


decir su dimensión en memoria, utilizando las palabras reservadas:

ReDim Y ReDim Preserve

Ejemplo:

Dim MiArreglo() As String ‘ Declaro mi arreglo


ReDim MiArreglo(2) ‘ Declaro nuevamente mi arreglo de dimension 3
MiArreglo(0) = “Uno” : MiArreglo(1) = “Dos” : MiArreglo(2) = “Tres”
ReDim Preserve MiArreglo(3) ‘Declaro nueva dimensión preservando los valores
MiArreglo(3) = “Cuatro”
MessageBox.Show(MiArreglo(0)) ‘Muestro el valor del primer dato

Nota : Podemos concatenar varias líneas de código separadas por :

Importante: Si deseamos conocer el tamaño o dimensión, podemos utilizar unmetodo de


los arreglos :

MiArreglo.Length

Ejemplo, utilizando el anterior podemos escribir

MessageBox.Show(MiArreglo.Length)

Nos visualizaría 4, que es la dimensión del arreglo

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 145


Importante: Si deseamos eliminar los elementos de un arreglo de forma rápida utilizamos
la palabra rservada Nothing, ejemplo:

MiArreglo = Nothing
If MiArreglo IsNothing then
MessageBox.Show(“ Nada”)
Else
MessageBox.Show(MiArreglo.Length) ‘presenta la dimension
Endif
Importante: Si deseamos copiar una matriz en otra podemos hacerlo de esta forma:
MiArreglo.CopyTo(OtroArreglo,0)

Ejemplo:
Private Sub Button1_Click_1(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim MiArreglo() As String = {“Mercurio”,”Venus”,”Tierra”}
Dim OtroArreglo() As String
ReDim OtroArreglo(MiArreglo.Lenght – 1)
MiArreglo.CopyTo(OtroArreglo,0)
MessageBox.Show(OtroArreglo(0))
End Sub

Para recorrer arrays multidimensionales, la clase Array dispone de varios miembros,


algunos de los cuales, describimos seguidamente.
Rank. Devuelve el número de dimensiones del array.
GetLength(Dimension). Devuelve el número de elementos de la dimensión de
array pasada como parámetro.
GetLowerBound(Dimension). Devuelve el número de índice inferior de la
dimensión pasada como parámetro.
GetUpperBound(Dimension). Devuelve el número de índice superior de la
dimensión pasada como parámetro.
Vamos a completar el ejemplo anterior con las líneas del siguiente código, necesarias
para recorrer el array multidimensional mostrado.
Private Sub Button1.Click….
TextBox1.Text = " "
' crear array multidimensional y rellenar de valores
Dim iDatos(2, 4) As Integer
Dim iContadorDimUno As Integer
Dim iContadorDimDos As Integer
Dim sTextoFila As String
' poner títulos de la fila y columnas del array a mostrar
TextBox1.Text = TextBox1.Text & "Matriz de (3,5) tres filas , cinco columnas " &
vbCrLf
TextBox1.Text = TextBox1.Text & vbCrLf

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 146


TextBox1.Text = TextBox1.Text & "Fila" & vbTab & "Col 1" & vbTab & "Col 2" &
_
vbTab & "Col 3" & vbTab & "Col 4" & vbTab & "Col 5" & vbCrLf
' El bucle externo recorre la primera dimensión las Filas
For iContadorDimUno = iDatos.GetLowerBound(0) To iDatos.GetUpperBound(0)
' aquí obtenemos el número de fila que se está procesando
sTextoFila = iContadorDimUno
‘ escribo el nuemro de la fila
TextBox1.Text = TextBox1.Text & sTextoFila + 1 & vbTab
' este bucle recorre la segunda dimensión las columnas
For iContadorDimDos = iDatos.GetLowerBound(1) To iDatos.GetUpperBound(1)
' TextBox1.Text = TextBox1.Text & vbTab & sTextoFila & _
iDatos(iContadorDimUno, _
iContadorDimDos) ' & vbTab
TextBox1.Text = TextBox1.Text & iDatos(iContadorDimUno, iContadorDimDos) _
& vbTab
Next
TextBox1.Text = TextBox1.Text & vbCrLf
Next
sTextoFila = ""
TextBox1.Text = TextBox1.Text & vbCrLf
TextBox1.Text = TextBox1.Text & "El número de dimensiones es: " & iDatos.Rank _
& vbCrLf
TextBox1.Text = TextBox1.Text & "El número total de elementos es: " & _
iDatos.Length & vbCrLf
End sub

Actividades de reforzamiento de lo a
aprendido

TAREAS PROGRAMACION DE TABLAS (ARREGLOS BIDIMENSIONALES)

1.- Construir un cuadro que contenga los costos fijos de cuatro productos cualesquiera, que
se producen en tres plantas diferentes de una empresa maquiladora (2 prog uno capturado
y otro inicializado).

2.- Construir un cuadro que contenga los ingresos mensuales por ventas durante los tres
primeros meses del ano de cuatro sucursales de una cadena de auto refacciones, agregar al
final una lista que muestre los ingresos mensuales totales por meses y una segunda lista
que muestre los ingresos mensuales totales por sucursal(2 progs uno capturado y otro
inicializado).

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 147


3.-Construir un cuadro que contenga las comisiones ganadas por tres vendedores, de los 5
tipos de linea blanca de conocida muebleria, ademas listas de comisiones totales y
promedios ganadas por los vendedores, asi como listas de comisiones totales y promedios
por tipo de linea blanca

Analizar este codigo:

' PARA TOTALES Y PROMEDIOS POR RENGLON (FILAS)

FOR R = 0 TO 3
FOR C = 0 TO 2
TOTRENG(R) = TOTRENG(R) + TABLA(R,C)
NEXT C
PROMRENG(R) = TOTRENG(R)/3
NEXT R

'PARA TOTALES Y PROMEDIOS POR COLUMNA

FOR C = 0 TO 2
FOR R = 0 TO 3
TOTCOL(C)=TOTCOL(C) + TABLA(R,C)
NEXT R
PROMCOL(C) = TOTCOL(C) / 4
NEXT C

4.9--Funciones del lenguaje integradas


Cada lenguaje dispone de un grupo de funciones de apoyo, para ayudar al programador
en su trabajo cotidiano. Las versiones anteriores de Visual Basic contenían un gran
número de funciones para realizar operaciones aritméticas, manipular cadenas, fechas,
etc.
VB.NET también tiene funciones para las operaciones antes comentadas. No obstante,
debido a la orientación a objetos sobre la que está construida la plataforma .NET, la
gran potencia a la hora de resolver cualquier situación la encontraremos en el gran
número de clases proporcionadas por el entorno para resolver las más variadas
situaciones, lo que veremos en el tema dedicado a OOP.
En este apartado y organizadas por categorías, vemos una pequeña muestra de las
funciones disponibles en VB.NET. Consulte el lector la documentación de la
plataforma, para obtener información más detallada de todas las funciones disponibles.
Funciones Numéricas
Int(Número), Fix(Número). Estas funciones devuelven la parte entera del
parámetro Número. La diferencia entre ambas reside en que cuando el parámetro pasado
es negativo, Int() devuelve el entero negativo menor o igual que Número, mientras
que Fix( ) devuelve el entero negativo mayor o igual que Número. Ver el Código
Dim Resultado As Integer

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 148


Resultado = Int(66.87) ' 66
Resultado = Fix(66.87) ' 66
Resultado = Int(-66.87) ' -67
Resultado = Fix(-66.87) ' –66

Randomize([Número]). Inicializa el generador de números aleatorios, que


utilizaremos posteriormente en la función Rnd( ). Opcionalmente recibe un número
como parámetro que sirve al generador como valor inicial o semilla para la creación
de estos números.

Rnd([Número]). Devuelve un número aleatorio de tipo Single, que será menor que 1,
pero mayor o igual a cero.
Podemos, opcionalmente, variar el modo de generación del número pasando un valor al
parámetro de esta función. En función de si el parámetro es mayor, menor de cero, o
cero, el comportamiento de Rnd( ) a la hora de generar el número será diferente. Ver el
Código
Dim Contador As Integer
Dim Aleatorio As Single
Randomize()
For Contador = 1 To 5
Aleatorio = Rnd()
MsgBox("Número generado: es "&, Aleatorio)
Next

El anterior código produce una salida similar a la mostrada en la Figura

Numero generado: 0,706402


Numero generado: 0,4058605
Numero generado: 0,337209
Numero generado: 0,8914912
Numero generado: 0,8711619
Generación de números aleatorios con Rnd( ).
Si necesitamos que el número aleatorio esté comprendido en un intervalo de
números enteros, utilizaremos la fórmula del Código para generarlo.
Int((LímiteSuperior - LímiteInferior + 1) * Rnd() + LímiteInferior)
El ejemplo del Código crea números aleatorios comprendidos entre el intervalo de los
números 7 y 12.
Dim Contador As Integer
Dim Aleatorio As Single
Randomize()
For Contador = 1 To 10
Aleatorio = Int((12 - 7 + 1) * Rnd() + 7)
MsgBox("Número generado: "& Aleatorio)
Next

Funciones Cadena de caracteres (Imports Microsoft.VisualBasic.Strings)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 149


Len(Cadena). Devuelve un número con la longitud de la cadena pasada como parámetro.
Ver el Código
Dim Longitud As Integer
Longitud = Len("comprobar cuantos caracteres hay")
MsgBox("La cadena tiene caracteres " & Longitud) ' 32

Space(Número). Devuelve una cadena de espacios en blanco, de una longitud igual al


número pasado como parámetro. Ver el Código.

Dim ConEspacios As String


ConEspacios = "Hola" & Space(7) & "a todos"
MsgBox("La cadena con espacios tiene el valor:" & ControlChars.CrLf &
ConEspacios)
' Hola a todos

Strings.InStr([Comienzo, ]CadenaBuscar, CadenaBuscada [, TipoComparación]).


Busca dentro de CadenaBuscar la cadena contenida en el parámetro CadenaBuscada.
Opcionalmente podemos establecer en Comienzo, la posición en la que comienza la
búsqueda y el tipo de comparación (texto, binaria) en el parámetro TipoComparación. Ver el
Código

Dim CadBuscar As String


Dim CadBuscada As String
Dim PosComienzo As Integer
CadBuscar = "El castillo del bosque"
PosComienzo = InStr(CadBuscar, "tillo")
MsgBox("La posición de comienzo de la cadena encontrada es: " & ,PosComienzo)
'7

Strings.Left(Cadena, Longitud). Esta función extrae, comenzando por la parte izquierda de


Cadena, una subcadena de Longitud de caracteres.

Strings.Right(Cadena, Longitud). Esta función extrae, comenzando por la parte derecha


de Cadena, una subcadena de Longitud de caracteres.

El Código muestra ejemplos de Left( ) y Right( ).

Dim CadIzquierda As String


Dim CadDerecha As String
CadIzquierda = Strings.Left("Especial", 3)
MsgBox("Resultado de la función Left(): "& CadIzquierda) ' Esp
CadDerecha = Strings.Right("Especial", 3)
MsgBox("Resultado de la función Right(): "& CadDerecha) ' ial

Mid(Cadena, Inicio [, Longitud]). Extrae de Cadena, comenzando en la posición Inicio,

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 150


una subcadena. Opcionalmente podemos utilizar el parámetro Longitud, para indicar el largo
de la subcadena. En caso de no utilizar este último parámetro, la subcadena se obtendrá
hasta el final. Ver Código

Dim MiCadena As String


Dim SubCadena As String
MiCadena = "El bosque encantado"
SubCadena = Strings.Mid(MiCadena, 6)
MsgBox("Subcadena hasta el final: "& SubCadena) ' sque encantado
SubCadena = Mid(MiCadena, 6, 3)
MsgBox("Subcadena de 3 caracteres: "& SubCadena) ' squ

Replace(Cadena,CadOrigen,CadNueva [,Inicio] [,Sustituciones]


[,TipoComparación]).
Esta función toma la cadena situada en el primer parámetro y busca la cadena
CadOrigen, sustituyendo las ocurrencias encontradas por la cadena CadNueva.
Opcionalmente, el parámetro Inicio especifica la posición en la que comenzará la
sustitución; el parámetro Sustituciones indica el número de sustituciones a realizar; y
TipoComparación indica como se realizarán las comparaciones (texto, binaria). Veamos
unos ejemplos en el Código
Dim MiCadena As String : Dim CadSustituida As String
MiCadena = "Este coche es especial"
CadSustituida = Replace(MiCadena, "es", "xx")
' resultado: Este coche xx xxpecial
MsgBox("Resultado del reemplazo en la cadena: "& CadSustituida)
' en el anterior ejemplo los dos primeros caracteres no se sustituyen porque
' no se ha especificado el tipo de comparación, que a continuación sí indicaremos
CadSustituida = Replace(MiCadena, "es", "xx", , , CompareMethod.Text)
' resultado: xxte coche xx xxpecial
' ahora sí se han sustituido todas las ocurrencias de "es"
MsgBox("Resultado del reemplazo en la cadena: "& CadSustituida)

Strings.LTrim(Cadena), RTrim(Cadena), Trim(Cadena). Estas funciones eliminan de


una cadena, los espacios en blanco a la izquierda en el caso de LTrim( ); los espacios
en blanco a la derecha en el caso de RTrim(); o los espacios en blanco a ambos lados Trim(
). Ver el Código

Dim CadEspacios As String : Dim CadResultante As String


CadEspacios = " Barco "
CadResultante = LTrim(CadEspacios) ' "Barco "
CadResultante = RTrim(CadEspacios) ' " Barco"
CadResultante = Trim(CadEspacios) ' "Barco"

UCase(Cadena), LCase(Cadena). Estas funciones, convierten la cadena pasada


como parámetro a mayúsculas y minúsculas respectivamente. Ver el Código .
Dim Cadena As String : Dim CadMay As String: Dim CadMin As String
Cadena = "Vamos a Convertir En Mayúsculas Y MinúscuLAS"

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 151


CadMay = UCase(Cadena)
CadMin = LCase(Cadena)
' "VAMOS A CONVERTIR EN MAYÚSCULAS Y MINÚSCULAS"
MsgBox("Conversión a mayúsculas: " & CadMay)
' "vamos a convertir en mayúsculas y minúsculas"
MsgBox("Conversión a minúsculas: " & CadMin)

Format(Expresión[,CadenaFormato][,PrimerDíaSemana[,PrimeraSemanaAño]).

Formatea la expresión pasada en el primer parámetro, empleando de forma opcional


una cadena para especificar el tipo de formateo a realizar. Si el valor a formatear es una
fecha, podemos utilizar los dos últimos parámetros para especificar el primer día de la
semana y la primera semana del año; estos dos últimos parámetros son enumeraciones,
cuyos valores aparecen automáticamente al asignar su valor. Consulte el lector, la
documentación de ayuda para más información.

Como cadena de formato, podemos utilizar los nombres predefinidos de formato, o una
serie de caracteres especiales, tanto para formateo de números como de fechas. En lo que
respecta a los nombres predefinidos, la Tabla 23 muestra algunos de los utilizados.
Nombre de formato Descripción

General Date Muestra una fecha con el formato largo del


sistema.

Short Date Muestra una fecha empleando el formato corto del


sistema.

Short Time Muestra un valor horario con el formato corto del


sistema.

Standard Muestra un número utilizando los caracteres de


separador de miles y decimales.

Currency Muestra un número con los caracteres


correspondientes a la moneda establecida en la
configuración regional del sistema.

Percent Muestra un número multiplicado por 100 y con el


carácter de tanto por ciento.

Nombres de formato para la función Format( ).


El Código fuente muestra algunos ejemplos de formateo con nombre
Dim MiFecha As Date
Dim MiNumero As Double
Dim ValorFormato As String
MiFecha = #7/19/2002 6:25:00 PM#
MiNumero = 1804
ValorFormato = Format(MiFecha, "Long Date")' "Viernes, 19 de julio de 2004”

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 152


ValorFormato = Format(MiFecha, "Short Date") ' "19/07/2002"
ValorFormato = Format(MiFecha, "Short Time") ' "18:25"
ValorFormato = Format(MiNumero, "Standard") ' "1.804,00"
ValorFormato = Format(MiNumero, "Currency") ' "1.804 pta"
ValorFormato = Format(MiNumero, "Percent") ' "180400,00%"

Para los caracteres especiales, la Tabla muestra un conjunto de los más habituales.

Carácter de Descripción
formato

: Separador de hora.

/ Separador de fecha.

d Visualiza el número de día sin cero a la


izquierda.
dd Visualiza el número de día con cero a la
izquierda.
ddd Visualiza el nombre del día abreviado.

dddd Visualiza el nombre del día completo.

M Visualiza el número de mes sin cero a la


izquierda.
MM Visualiza el número de mes con cero a
la izquierda.

MMM Visualiza el nombre del mes abreviado.

MMMM Visualiza el nombre del mes completo.

yy Visualiza dos dígitos para el año.

yyyy Visualiza cuatro dígitos para el año.

H Visualiza la hora sin cero a la izquierda.

HH Visualiza la hora con cero a la izquierda.

m Visualiza los minutos cero a la izquierda.

mm Visualiza los minutos con cero a la izquierda.

s Visualiza los segundos cero a la izquierda.

ss Visualiza los segundos con cero a la izquierda.

0 En valores numéricos, muestra un dígito o cero.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 153


# En valores numéricos, muestra un dígito o nada.

, Separador de millar.

. Separador decimal.

Caracteres de formato para la función Format( ).

El Código muestra algunos ejemplos de formato con caracteres especiales.


Dim MiFecha As Date
Dim MiNumero As Double
Dim ValorFormato As String
MiFecha = #7/19/2002 6:25:00 PM#
MiNumero = 16587.097
ValorFormato = Format(MiFecha, "dddd d/MMM/yyyy") ' "Viernes 19/jul/2002"
ValorFormato = Format(MiFecha, "HH:mm") ' "18:25"
ValorFormato = Format(MiNumero, "#,#.00") ' "16.587,10"

StrConv(Cadena, TipoConversión [,IDLocal]). Realiza una conversión de la cadena


pasada como parámetro, utilizando algunos de los valores de la enumeración
TipoConversión. Opcionalmente podemos pasar también un valor correspondiente al
identificador local del sistema. Ver el Código fuente

Dim MiCadena As String


Dim Conversion As String
MiCadena = "el tren llegó puntual"
' convertir a mayúscula

Conversion = StrConv(MiCadena, VbStrConv.UpperCase)


' convertir a minúscula
Conversion = StrConv(MiCadena, VbStrConv.LowerCase)
' convertir a mayúscula la primera letra de cada palabra
Conversion = StrConv(MiCadena, VbStrConv.ProperCase)
MessageBox.Show("Conversion”)
Fecha y hora
Now( ). Devuelve un valor de tipo Date con la fecha y hora del sistema.
DateAdd(TipoIntervalo, ValorIntervalo, Fecha). Suma o resta a una fecha, un
intervalo determinado por el parámetro TipoIntervalo. El intervalo a utilizar pueden ser
días, semanas, meses, etc. Para determinar si se realiza una suma o resta, ValorIntervalo
deberá ser positivo o negativo respectivamente.
DateDiff(TipoIntervalo, FechaPrimera, FechaSegunda). Calcula la diferencia
existente entre dos fechas. En función de TipoIntervalo, la diferencia calculada serán días,
horas, meses, años, etc.
DatePart(TipoIntervalo, Fecha). Extrae la parte de una fecha indicada en
TipoIntervalo. Podemos obtener, el día, mes, año, día de la semana, etc.
El Código fuente muestra un conjunto de ejemplos que utilizan las funciones para

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 154


manipular fechas.
Dim MiFecha As Date
Dim FechaPosterior As Date
Dim DiasDiferencia As Long
Dim ParteFecha As Integer
MiFecha = Now() ' #1/19/2012 12:27:08 PM#
FechaPosterior = DateAdd(DateInterval.Month, 2, MiFecha) ' #3/19/2012 12:27:08
PM#
DiasDiferencia = DateDiff(DateInterval.Day, MiFecha, FechaPosterior) ' 59
ParteFecha = DatePart(DateInterval.Year, MiFecha) ' 2012
MessageBox.Show("Dias de diferencias " & DiasDiferencia)

Funciones matemáticas
Las principales funciones matemáticas provistas por Visual Basic son:

 Math.Abs(): Devuelve el valor absoluto de una expresión numérica.


 Math.Atn(): Devuelve el arco tangente de un número.
 Math.Cos(): Devuelve el coseno de un ángulo.
 Math.Exp(): Devuelve el número "e" elevado a una potencia.
 Math.Log(): Devuelve el logaritmo natural de un número.
 Math.Sgn(): Devuelve un valor indicando el signo de un número.
 Math.Sin(): Devuelve el seno de un ángulo.
 Math.Sqr(): Devuelve la raíz cuadrada de un número.
 Math.Tan(): Devuelve la tangente de un ángulo.

4.10.-PROCEDIMIENTOS O SUBRUTINAS EN VISUAL BASIC NET

Recordar que un objeto presenta tres aspectos, propiedades, metodos y eventos, en esta
unidad se analizan algunos elementos que intervienen en la definicion de un metodo.

Estamos hablando de los llamados procedimientos y funciones, que quede claro que
procedimientos y funciones son solo algunos aspectos (importantes) de la definicion de un
metodo, pero que existen elementos tan o mas importantes que los analizados en esta
unidad. Un procedimiento es un grupo de instrucciones, variables, constantes, etc, que
estan disenados con un proposito particular y tiene su nombre propio.

Es decir un procedimiento es un modulo de un programa que realiza tareas especificas y


que no puede regresar valores al programa principal u a otro procedimiento que lo este
invocando. Despues de escribir un procedimiento se usara su propio nombre como una
sola instruccion o llamada al procedimiento usando el formato:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 155


CALL NOMPROC()

El formato para construir un procedimiento o subrutina en VISUAL BASIC NET es:

Sub NomProc()
Instrucciones
End Sub

Un programa puede tener tantos procedimientos o subrutinas como se deseen, para hacer
una llamada o invocacion al procedimiento durante la ejecucion de un programa solo se
debera escribir el nombre del procedimiento y los parentesis en blanco.

Programa

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click

' llamando, invocando o activando procedimiento uno


Call PROC1()
End Sub

Sub PROC1()
Label2.Text = EDAD.Text * 12
End Sub

Corrida

Como se observa un procedimiento puede ser un programa completo.

Actividades de reforzamiento de
MSc. Ing. Jorge PradoloD.
aprendido Docente: Universidad Nacional de Ingeniería 156
EJERCICIOS DE PROGRAMACION DE FUNCIONES

Construir tres programas que contengan los procedimientos abajo del sub buttonclick().
a) Convertir $800.00 Cordobas a dolares.
b) Calcular el Area de un triangulo
c) Deplegar una Boleta de calificaciones.

PARAMETROS EN VISUAL BASIC


Un parametro es una variable que puede pasar su valor a un procedimiento desde el principal
o desde otro procedimiento.
Existen ocasiones en que es necesario mandar al procedimiento ciertos valores para que los
use en algun proceso.

Estos valores que se pasan del cuerpo principal del programa o de un procedimiento a otros
procedimientos se llaman parametros. Entonces la declaracion completa de un
procedimiento es :

SUB NOMPROC(lista de parametros)


cuerpo de instrucciones
END SUB
Donde lista de parametros es una o mas variables separadas por comas como lo muestra el
pograma ejemplo. Programa

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles Button1.Click
Dim nom As String
nom = "pepe"
'Se puede mandar como parametro un dato, variable 'o expresion algebraica
Call PROC1(3.75, nom, 4 + 8)
End Sub

Sub PROC1(ByVal deci As Single, ByVal nom As String, ByVal suma As Integer)
' pero siempre se recibe en una variable
Label2.Text = EDAD.Text + deci + suma
Label3.Text = nom
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 157


Observar que en el procedimiento los parametros crean dos variables de manera local, es
decir variables que solo se pueden usar dentro del procedimiento estas variables son quienes
reciben los datos o valores.

REGLAS PARA EL USO DE PARAMETROS:


1.- Cuando se usan variables como parametros la variable que se manda debe ser declarada
dentro del principal o del procedimiento de donde se esta enviando.
2.- La variable que se manda tiene un nombre, la que se recibe puede tener otro nombre o el
mismo nombre por claridad de programa, pero recordar que internamente en la memoria del
computador existiran dos variables diferentes.
3.- La cantidad de variables que se envian deben ser igual en cantidad, orden y tipo a las
variables que reciben.
4.- La variable que se recibe tiene un ambito local dentro del procedimiento, es decir solo la
puede usar ese procedimiento.
5.- Se puede mandar a un procedimiento un dato, una variable (como lo muestran los
ejemplos) o una expresion algebraica (no ecuacion o formula) pero siempre se deberan recibir
en una variable.
Corrida

Actividad de reforzamiento de lo
aprendido

EJERCICIOS DE PROGRAMACION DE FUNCIONES

1.- En una VENTANA recoger 3 calificaciones en el onclick, calcular promedio en


procedimiento uno y desplegar nombre y promedio en un segundo procedimiento
2,- Construir una tabla de multiplicar que el usuario indique, captura y control de ciclo en
button_click, calculo y despliegue en un procedimiento usar un solo listbox para la tabla
resultado.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 158


3.- Construir un procedimiento que reciba un numero entero y que mande llamar a un segundo
procedimiento pasando el letrero “PAR O IMPAR”

FUNCIONES EN VISUAL BASIC NET


Una funcion es un modulo de un programa separado del cuerpo principal que realiza una
tarea especifica y que puede regresar un valor a la parte principal del programa u otra
funcion o procedimiento que la invoque.
La forma general de una funcion es:

Function NOMFUNCION(parametros)
instrucciones
NOMFUNCION = cargarlo porque es quien regresa el dato
End Function

La lista de parametros formales es una lista de variables separadas por comas (,) que
almacenaran los valores que reciba la funcion estas variables actuan como locales dentro
del cuerpo de la funcion. Aunque no se ocupen parametros los parentesis son requeridos.

Dentro del cuerpo de la funcion deber haber una instruccion que cargue el NOMFUNCION
para regresar el valor, de esta manera se regresan los datos.
Sin embargo es de considerar que NOMFUNCION puede regresar un dato, una variable o
una expresion algebraica (no ecuacion o formula) como lo muestran los siguientes
ejemplos:

a) NOMFUNCION = 3.1416
b) NOMFUNCION = area
c) NOMFUNCION = x + 15 / 2

Recordar ademas:

a) Una funcion no se llama usando CALL


b) Cuando se llame a una funcion debera haber una variable que reciba el valor que
regresara la funcion, es decir generalmente se llama una funcion mediante una sentencia
de asignacion, por ejemplo resultado = funcion(5, 3.1416)

Programa

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click
'Creando variable que recibira el valor que regrese la funcion
Dim alfa as integer
'llamando la funcion y mandandole datos o parámetros observar que se llama por
'igualdad
alfa = FUNCION1(500)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 159


' Aunque se puede llamarla directamente y cuantas veces sea necesario
Label1.Text = FUNCION1(100) - alfa
End Sub

Function FUNCION1(ByVal varuno As Integer)


' cargando y regresando el nomfuncion
FUNCION1 = 100 + varuno
End Function
Corrida

Nota: Es permitido cargar más de


un NOMFUNCION en el cuerpo
de instrucciones sobre todo en
condiciones, pero solo uno de ellos
se ejecutara

Ejemplo;

if suma >= 10 then


funcion50 = 300
else
funcion50 = 20
end if

TIPOS USUALES DE FUNCIONES.

Las primeras son de tipo computacional que son diseñadas para realizar operaciones con
los argumentos y regresa un valor basado en el resultado de esa operacion.

Las segundas funciones son aquellas que manipulan informacion y regresan un valor que
indican la terminacion o la falla de esa manipulacion.

Las terceras son aquellas que no regresan ningun valor, es decir son estrictamenta
procedurales. Esto quiere decir que en general toda operacion o calculo en un programa
debera convertirse a una o muchas funciones y el resto deberan ser procedimientos.

ARREGLOS COMO PARAMETROS

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 160


Para pasar un arreglo completo como parametro a un procedimiento o a una funcion solo
se manda el nombre del arreglo sin corchetes e indices, en el procedimiento o funcion que
recibe solo se declara un arreglo del mismo tipo y se puede usar el mismo o diferente
nombre del arreglo sin corchetes e indices.

Sin embargo es conveniente aclarar, que a diferencia de variables escalares normales visual
basic no genera una nueva variable en memoria ni tampoco copia los datos al arreglo que
recibe, en su lugar visual basic sigue usando los datos que estan en el arreglo original, es
por esta razon que cambios que se le hagan a los datos del arreglo que recibe realmente se
esta haciendo al arreglo original como lo muestra el siguiente ejemplo:

Programa

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles Button1.Click

' creando y cargando una lista local con 5 elementos


Dim lista1() As Integer = {1, 2, 3, 4, 5}
' pasandola a un procedimiento observar que se pasa sin parentesis
Call PROC1(lista1)
' desplegando lista original y observar el resultado
Dim r As Integer
For r = 0 To 4
LISTA.Items.Add(lista1(r))
Next r
End Sub

Sub PROC1(ByVal vector)


' recibiendola con otro nombre y ' sumando a vector + 100
Dim r As Integer
For r = 0 To 4
vector(r) = vector(r) + 100
Next r
End Sub
Es de recordar que los cambios que le hagan
Corrida al arreglo dentro del procedimiento se
reflejaran en el arreglo original, es por esto
que si se quiere modificar un arreglo en un
procedimiento funcion no hay necesidad de
regresar ningun valor y por tanto no se
ocupan funciones.

Solo para los casos que se quiera regresar


algun dato especial del arreglo, por ejemplo
regresar el primer dato par, o la suma de
todos los elementos del arrreglo o el
promedio de todos sus elementos, etc etc
MSc. Ing. Jorge Prado D. Docente: etc,
Universidad Nacional
solo en casos de Ingeniería
como estos se mandara161
una arreglo a una funcion.
Actividades de reforzamiento de lo aprendido

EJERCICIOS DE PROGRAMACION DE FUNCIONES


1.- Capturar 3 calificaciones y nombre en un procedimiento, calcular promedio en una
funcion, desplegar en otro procedimiento, BUTTONCLICK SOLO ACTIVA EL PRIMER
PROCEDIMIENTO
2.- Crear una tabla de multiplicar, captura y control de ciclo en el principal (BUTTONCLICK),
operaciones en una funcion, despliegue en el principal.
3.- Inicializar 10 edades en el principal(buttonclick) mandar la lista a un procedimiento que
la convierte a meses, desplegar en principal.
4.- Capturar un arreglo de 7 ciudades en un primer procedimiento, sortear en un segundo
y desplegar en un tercero, la lista original y la lista ordenada.

Funciones de comprobación de tipos de datos


Si tenemos desactivada la comprobación de tipos con Option Strict, pero en ciertas
situaciones necesitamos comprobar si determinada variable o expresión contienen un valor
numérico, fecha, etc., el lenguaje nos proporciona para ello, algunas funciones con las que
podremos comprobar el tipo de dato, para evitar posibles errores.

IsNumeric( ). Esta función devuelve un valor lógico indicando si la expresión que


pasamos como parámetro contiene un número o una cadena que pueda ser convertida a
número. Ver el Código

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 162


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
Dim Valor As Object
Dim Total As Integer
Valor = Inputbox(“ Introduzca un valor”)
If IsNumeric(Valor) Then
Total = Valor + 100
MsgBox("Resultado: "& Total)
Else
MsgBox("El valor introducido no es numérico")
End If
End Sub

IsDate( ). Esta función devuelve un valor lógico indicando si la expresión que pasamos
como parámetro contiene una fecha o una cadena que pueda ser convertida a fecha. Ver
el Código
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
Dim Valor As Object
Dim UnaFecha As Date
Valor = Inputbox(“ Introduzca un valor”)
If IsDate(Valor) Then
UnaFecha = Valor
MsgBox("La fecha es: "& UnaFecha)
Else
MsgBox("El valor introducido no es una fecha")
End If
End Sub

IsArray( ). Esta función devuelve un valor lógico indicando si la expresión que


pasamos como parámetro contiene un array. Ver el Código
.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles Button1.Click
Dim Colores() As String = {"Verde", "Azul", "Rojo"}
Verificar(Colores)
Verificar("prueba")
End Sub

Public Sub Verificar(ByVal ValorPasado As Object)


' comprobar si el parámetro contiene un array
If IsArray(ValorPasado) Then
MsgBox("El parámetro pasado es un array")
Else
MsgBox("El parámetro pasado no es un array")

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 163


End If
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 164


5.- Programando con controles en Visual Basic
Los controles proporcionan al usuario el medio para comunicarse con nuestro
formulario, y en definitiva, con la aplicación. Por ello, en los siguientes apartados,
mostraremos los principales aspectos que debemos tener en cuenta a la hora de su
creación, manipulación y codificación.
También realizaremos una revisión de los principales controles, mostrando
algunas de sus características más destacadas.

5.1.-El Cuadro de herramientas


Una vez creado un proyecto, o después de añadir un nuevo formulario, para utilizar
controles en el mismo, tendremos que tomarlos de la ventana Cuadro de herramientas
disponible en el IDE de VS.NET, y añadirlos al formulario. Ver Figura

Uso del ToolBox

El ToolBox es la caja de herramientas donde se encuentran los controles que se van ha usar
para diseñar la interface de los diferentes tipos de aplicaciones, este varía de acuerdo al tipo
de plantilla elegida. A continuación se presenta el ToolBox cuando elegimos una plantilla
“Windows Application”; éste presenta varias fichas: “Windows Forms”, “Data”,
“Components” y “General”.

Figura 3.2: ToolBox para Aplicaciones Windows

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 165


Para usar un control del ToolBox solo hay que elegir la ficha adecuada y luego seleccionar
el control y arrastrarlo sobre el formulario o contenedor donde se desea ubicarlo, también se
puede dar doble clic sobre el control y aparecerá por defecto en la posición 0,0 del formulario
(antes se ubicaba al centro de éste).
Como habrá comprobado el lector, el número de controles del cuadro de herramientas
es muy numeroso, por lo que en los próximos apartados, vamos a trabajar con los que se
consideran controles básicos o estándar, dada su gran frecuencia de uso. La Tabla
relaciona este conjunto de controles básico, junto a una breve descripción.

Insertar un control en el formulario


Para añadir un control en el formulario, proceso que también se conoce como dibujar
un control, debemos seleccionar primeramente el control a utilizar de la lista que
aparece en el cuadro de herramientas.

Una vez localizado el control, haremos doble clic sobre él, o pulsaremos [INTRO], lo que
añadirá una copia del mismo en el formulario, que después, mediante el ratón o teclado,
situaremos en la posición adecuada.

Otra técnica, esta más habitual, consiste en hacer clic sobre el control, situar el cursor del
ratón en la superficie del formulario y hacer clic en él, arrastrando hasta dar la forma
deseada; de esta manera, proporcionamos al control en un solo paso la ubicación y tamaño
iniciales.

Dibujemos, a modo de práctica, un control Button sobre el formulario, con un aspecto


similar al mostrado en la

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 166


Un control, al igual que un formulario, dispone a su alrededor de un conjunto de guías de
redimensión, de modo que si después de situarlo en el formulario, queremos modificar su
tamaño, sólo tenemos que hacer clic sobre alguna de estas guías, y arrastrar modificando las
dimensiones del control.

Además de utilizando el ratón, podemos desplazar un control, manteniendo


pulsada la tecla[CONTROL], y pulsando además, algunas de las teclas de dirección.

Ajuste de la cuadrícula de diseño del formulario


La cuadrícula de diseño del formulario, consiste en el conjunto de líneas de puntos
que surcan la superficie del formulario, y nos sirven como ayuda, a la hora de realizar
un ajuste preciso de un control en una posición determinada.

Si el lector ya ha realizado algunas prácticas situando controles en el formulario, se percatará


de que cuando movemos un control con el ratón, dicho control se ajusta a la cuadrícula
obligatoriamente, por lo que no podemos ubicarlo entre dos líneas de puntos de la cuadrícula.
Para solventar este problema tenemos algunas soluciones que proponemos a continuación:

La más simple y directa, consiste en acceder a la ventana de propiedades del


formulario, y en la propiedad GridSize, cambiar los valores de espaciado de puntos que
tiene la rejilla. Cuanto menor sea ese valor, más junta estará la trama de puntos de la
rejilla, con lo que podremos ajustar de forma más exacta el control. Este ajuste es válido
sólo para el formulario sobre el que lo aplicamos. Probemos por ejemplo, a introducir 5 en
cada valor, como muestra la Figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 167


Cambiando el tamaño de la cuadrícula de diseño del formulario.
El otro modo consiste en asignar en el formulario, a la propiedad SnapToGrid, el valor
False; esto deshabilita el ajuste a la cuadrícula automático de los controles, con lo que
perdemos en precisión de ajuste, pero ganamos en libertad de ubicación para el control.
Si no queremos que la cuadrícula se visualice, asignaremos False a la propiedad DrawGrid
del formulario.
Los anteriores ajustes los podemos realizar también de modo genérico para todos los
formularios. Seleccionaremos para ello, la opción de menú del IDE Herramientas +
Opciones, y en la ventana Opciones, haremos clic sobre el elemento Diseñador de
Windows Forms. En el panel derecho de esta ventana, podremos configurar estas
propiedades de modo general para todo el IDE. Ver Figura

Ajuste general de las propiedades para la cuadrícula de diseño de


formularios.
Organización-formato múltiple de controles

Cuando tenemos un grupo numeroso de controles en el formulario, que necesitamos


mover de posición, o cambiar su tamaño, para redistribuir el espacio; podemos optar por
cambiar uno a uno los controles, tarea pesada y nada aconsejable; o bien, podemos
seleccionar todos los controles a modificar, y realizar esta tarea en un único paso,
mediante las opciones del menú Formato del IDE. Supongamos que en el formulario
tenemos dos controles Button y un ListBox distribuidos como muestra la Figura

En primer lugar, para seleccionarlos todos, debemos hacer clic sobre el formulario y
arrastrar, de modo que el rectángulo de selección que aparece, abarque a los controles,

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 168


que quedarán con sus correspondientes marcas de redimensión visibles, señal de que están
seleccionados.
En este punto, podemos hacer clic en uno de los controles y desplazarlos todos
conjuntamente por el formulario, o bien, hacer clic en una de las guías de redimensión y
cambiar su tamaño, lo que afectará a todos los controles seleccionados. Si necesitamos
de alguna acción especial, utilizaremos las opciones del menú Formato del IDE.
Por ejemplo, podemos ejecutar la opción Formato + Alinear + Lados izquierdos, de modo
que todos los controles se alinearán por la izquierda, tomando como referencia el control que
tiene las marcas de redimensión negras. Ver Figura

Después ejecutaremos la opción de menú Formato + Igualar tamaño + Ambos, que


ajustará tanto el ancho como el alto de todos los controles seleccionados. Ver Figura

Igualando tamaño de controles.


Para evitar que, una vez completado el diseño y ajuste de todos lo controles, accidentalmente
podamos modificar alguno, seleccionaremos la opción de menú Formato + Bloquear
controles, que bloqueará
los controles seleccionados, impidiendo que puedan ser movidos o modificado su
tamaño. Para desbloquear los controles del formulario, debemos seleccionar al menos uno
y volver a utilizar esta opción de menú, que desbloqueará todos los controles.
Una característica interesante del bloqueo de controles, consiste en que una vez que
tengamos bloqueados los controles del formulario, si añadimos un nuevo control, este
no estará inicialmente bloqueado, lo que facilita su diseño. Una vez que hayamos finalizado
de diseñar el último control, lo seleccionaremos en el formulario y seleccionaremos la
opción de bloqueo de controles, de modo que ya estarán bloqueados todos de nuevo.
El menú Formato de VS.NET consta de un numeroso conjunto de opciones. Acabamos
de ver una muestra de sus posibilidades, por lo que recomendamos al lector, que realice

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 169


pruebas con el resto de opciones, para ver todas las posibilidades en cuanto a la
disposición de los controles dentro del formulario.
Para ilustrar mejor la funcionalidad que podemos obtener de Windows tenemos la
figura 4.1, que resume los principales objetos usados en Windows, para lo cual se
parte de la clase base llamada “System”, luego se muestran algunos de los objetos
de la clase “Drawing” y de la clase “WinForms” anteriormente comentadas.

Figura 3.1: Modelo de Objetos para Windows

Windows

Forms

Form

TextBox

Cabe comentar que dentro de la clase Windows encontramos definido el formulario


Cipboard
y los controles para Windows (Label, Button, TextBox, Menu, etc), así como también
algunos objetos no visuales de utilidad como Application (reemplaza al objeto App
Screen
de VB6), Clipboard, Help, Screen, etc.
5-2-Controles Windows Basicos

5.2.1.Objeto Formulario

El objeto Formulario es el contenedor principal de toda aplicación para Windows y


se encuentra en el siguiente NameSpace:
“System.Windows.Forms.Form”
En Visual Studio .NET el formulario ha sufrido muchos cambios, tanto en propiedades,
métodos y eventos, tal como se muestra en los siguientes cuadros:

Propiedades

Propiedad
Descripción
Autoscroll Es una nueva propiedad que permite desplazarse por el
formulario a través de una barra si es que los controles
sobrepasan el área cliente.

Backcolor Especifica el color de fondo del formulario.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 170


BackgroundImag Antes llamada Picture. Permite mostrar una imagen de fondo
e sobre el formulario, tiene 2 tamaños: cascada y centrado en
pantalla.

BorderStyle Controla la apariencia del borde del formulario y los controles


que se presentan en la barra de título. Tiene 6 opciones.

ControlBox Si esta en True muestra el menú de controles de la barra de


título, si esta en False no los muestra.

Cursor Especifica el cursor que aparecerá al situar el mouse sobre el


formulario. Antes era la propiedad MousePointer y si se quería
un cursor personalizado se configuraba MouseIcon, ahora solo
existe Cursor y sus gráficas son vistas en la lista.

Font Configura la fuente de los textos de los controles ubicados en


el formulario y de los textos mostrados con métodos de dibujo.

Forecolor Especifica el color del texto de los controles (excepto el


TextBox) y de los textos mostrados con métodos de dibujo.

GridSize Determina el tamaño de las rejillas que se muestran en tiempo


de diseño para diseñar controles.

Icon Indica el icono del formulario, este se muestra en la barra de


título de la ventana y en la barra de tareas de Windows.

IsMDIContainer Determina si es que el formulario es un MDI, antes se creaba


un formulario MDI añadiéndolo del menú “Project” y un
formulario hijo configurando la propiedad MDIChild en True.
Ahora solo se configura para ambos la propiedad
IsMDIContainer.

Location Indica la posición del formulario con respecto a la esquina


superior izquierda de la pantalla. Antes había que configurar la
propiedad Top y Left, ahora los valores de X e Y.

Opacity Es una nueva propiedad, que indica la forma de visualización


del formulario, que puede ser desde opaco (100%) hasta
transparente (0%). Antes para hacer transparente se usaba la
API SetWindowRgn

RightToLeft Determina la alineación de los textos con respecto a sus


controles, por defecto es No, es decir se alinean de izquierda a
derecha; si es True se alinearán de derecha a izquierda.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 171


Size Configura el tamaño del formulario en píxeles.

StartPosition Indica la posición en que aparecerá por primera vez el


formulario con respecto a la pantalla. Tiene 5 opciones.

Text Permite mostrar el texto de la barra de título en el formulario.

TopMost Posiciona en primer plano la ventana, siempre y cuando no este


desactivada. Antes se podía hacer esto con la API
WindowsOnTop.

WindowState Determina la forma en que se presentará la ventana, puede ser


Normal, Minimizada o Maximizada.

Métodos

Método
Descripción
Activate Activa el formulario y le da el foco.

ActivateControl Activa un control del formulario.

Close Cierra un formulario descargándolo de la memoria.

Focus Pone el foco sobre el formulario.

Hide Oculta el formulario, sin descargarlo de la memoria.

Refresh Repinta el formulario y sus controles.

SetLocation Ubica el formulario en una cierta posición de la pantalla.

SetSize Configura el tamaño de la ventana en píxeles.

Show Muestra un formulario como ventana no modal (modeles).

ShowDialog Muestra un formulario como ventana modal (modal).

Eventos

Evento
Descripción
Activated Ocurre al activarse el formulario.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 172


Click Se desencadena al dar clic con el mouse sobre el formulario.

Closed Se habilita al cerrar el formulario. Es similar al evento Unload


de Visual Basic 6.

Closing Ocurre mientras se está cerrando el formulario. Es similar al


evento QueryClose de Visual Basic 6. También se puede
cancelar la salida.

Deactivated Ocurre al desactivarse el formulario.

DoubleClick Se desencadena al dar doble clic con el mouse sobre el


formulario.

GotFocus Ocurre al ingresar el foco sobre el formulario.

Load Se produce al cargar los controles sobre el formulario

LostFocus Ocurre al salir el foco del formulario.

MouseEnter Se habilita al ingresar el mouse sobre el área cliente del


formulario.

MouseLeave Se habilita al salir el mouse del área cliente del formulario.

MouseMove Se desencadena al pasar el mouse sobre el formulario.

Move Este evento se habilita al mover la ventana o formulario.

Paint Ocurre al pintarse la ventana en pantalla.

Resize Ocurre cada vez que se modifica de tamaño el formulario.

5.2.2.- Control Label

El control Label o Etiqueta, muestra un texto informativo al usuario. Podemos utilizar


este control como complemento a otro control, por ejemplo, situándolo junto a un
TextBox, de modo que indiquemos al usuario el tipo de dato que esperamos que
introduzca en la caja de texto.
Se trata de un control estático; esto quiere decir que el usuario no puede interaccionar
con él, a diferencia, por ejemplo, de un control Button, sobre el que sí podemos actuar

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 173


pulsándolo; o de un TextBox, en el que podemos escribir texto.
Una de sus propiedades es BorderStyle, que permite definir un borde o recuadro alrededor
del control, o que dicho borde tenga un efecto 3D; por defecto se muestra sin borde. Veamos
unos ejemplos en la Figura

Controles Label.

Propiedades

Propiedad
Descripción
Anchor Es una nueva propiedad que permite ajustar el ancho del
control.

AutoSize Ajusta el texto de la etiqueta al tamaño del control.

Backcolor Especifica el color de fondo de la etiqueta.

BorderStyle Controla la apariencia del borde de la etiqueta. Tiene 3


opciones.

Cursor Especifica el cursor que aparece al situar el mouse sobre la


etiqueta.

Dock Da la posibilidad de acoplar la etiqueta a un lado del


contenedor, puede ser arriba, abajo, izquierda, derecha o al
centro.

Enabled Habilita o deshabilita la etiqueta.

Font Configura la fuente del texto de la etiqueta.

Forecolor Especifica el color del texto de la etiqueta.

Location Indica la posición de la etiqueta con respecto a su contenedor.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 174


Locked Bloquea el control para que no se mueva o modifique de
tamaño.

RightToLeft Determina la alineación del texto con respecto al control.

Size Configura el tamaño del control en píxeles.

Text Visualiza el texto de la etiqueta.

TextAlign Alinea el texto hacia el control, sea: izquierda, derecha o centro.

Visible Visualiza o no el control.

Métodos

Método
Descripción
FindForm Devuelve el formulario en el que se encuentra el control.

Focus Pone el foco sobre la etiqueta.

Hide Oculta la etiqueta, sin descargarla de la memoria.

Refresh Repinta la etiqueta.

SetLocation Ubica la etiqueta en una cierta posición de la pantalla.

SetSize Configura el tamaño de la etiqueta.

Show Pone visible la etiqueta.

Eventos

Evento
Descripción
Click Se desencadena al dar clic con el mouse sobre la etiqueta.

DoubleClick Se desencadena al dar doble clic con el mouse sobre la


etiqueta.

GotFocus Ocurre al ingresar el foco sobre el control.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 175


LostFocus Ocurre al salir el foco del control.

MouseEnter Se habilita al ingresar el mouse sobre la etiqueta.

MouseLeave Se habilita al salir el mouse de la etiqueta.

MouseMove Se desencadena al pasar el mouse sobre la etiqueta.

5.2.3.-Control TextBox
Un control TextBox muestra un recuadro en el que podemos introducir texto. Para poder
escribir texto en un control de este tipo, debemos darle primeramente el foco, lo que
detectaremos cuando el control muestre el cursor de escritura en su interior.
Entre las propiedades disponibles por este control, destacaremos las siguientes.

Control TextBox

Propiedades

Este control tiene propiedades similares al control Label, entre aquéllas propiedades
exclusivas de este control tenemos:

Propiedad
Descripción
Autosize Cuando esta propiedad tenga el valor True, al modificar el tamaño del
tipo de letra del control, dicho control se redimensionará
automáticamente, ajustando su tamaño al del tipo de letra establecido.

CharacterCasing Nueva propiedad que convierte a mayúsculas o minúsculas el texto.

Enable Contiene un valor lógico mediante el que indicamos si el control está o


No habilitado para poder escribir texto sobre él.

Font Cambia el tipo de letra y todas las características del tipo elegido.

Lines Muestra el contenido de cada línea del texto.

MaxLength Determina el número de caracteres que se pueden ingresar en éste.

MultiLine Si es True se pueden escribir varias líneas de texto.

PasswordChar Señala el carácter que aparecerá como mascara de entrada.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 176


ReadOnly Indica que el control solo se puede ver pero no editar. Antes se
llamaba Locked.

ScrollBars Habilita las barras de desplazamiento si el control es multilínea.


Text Cadena con el texto del control.
WordWrap Cambia de línea al llegar al final de un texto multilínea.

Métodos

Método
Descripción
AppendText Añade texto al final del texto actual.

Clear Borra el contenido del cuadro de texto.

Copy Copia el texto y lo envía al portapapeles.

Cut Corta el texto y lo envía al portapapeles.

Paste Pega el texto del portapapeles al cuadro.

ResetText Inicializa el texto.

Select Selecciona el texto.

Undo Deshace el último cambio en el texto.

Eventos

Evento
Descripción
KeyDown Ocurre al pulsar hacia abajo una tecla extendida.

KeyPress Ocurre al pulsar una tecla normal. También se desencadena


antes el evento KeyDown y después el evento KeyUp.

KeyUp Ocurre al soltar una tecla extendida previamente pulsada.

TextChanged Es un nuevo evento que reemplaza al evento change, es decir


ocurre al cambiar el texto.

Validated Se habilita después de validarse el control.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 177


Validating Se habilita cuando el control está validándose.

La Figura muestra un formulario con varios controles TextBox, a los cuales se han
aplicado diferentes efectos mediante sus propiedades.

Pruebas con controles TextBox.


Al comenzar a ejecutar el programa, observaremos que el foco de entrada no está situado
en el primer TextBox del formulario. Para asignar por código el foco a un determinado
control, disponemos del método Focus( ). En este caso, al pulsar el botón Foco nombre,
desviamos el foco al primer TextBox del formulario. Ver Código fuente
Private Sub btnFoco_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnFoco.Click
Me.txtNombre.Focus()
End Sub
Observe el lector, que en el botón Foco nombre, que acabamos de mencionar, la letra F se
encuentra subrayada, actuando de acelerador o hotkey. De este modo, no es necesario
pulsar con el ratón sobre ese botón para ejecutarlo, basta con pulsar la tecla
[CONTROL] junto a la letra subrayada para conseguir el mismo efecto.
Para definir una tecla aceleradora en un control, debemos anteponer el carácter & a la letra
que vamos a definir como acelerador, en este ejemplo se ha logrado con &Foco nombre.
Por otro lado, mediante el botón btnSoloLectura conseguimos activar/desactivar la
propiedad ReadOnly del TextBox txtNombre, cambiando el estado de dicha propiedad
en cada pulsación del botón. Ver Código fuente
Private Sub btnSoloLectura_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnSoloLectura.Click
If (Me.txtNombre.ReadOnly) Then
Me.txtNombre.ReadOnly = False
Else
Me.txtNombre.ReadOnly = True
End If
End Sub-

Sin embargo, hay otro modo mucho más eficiente de cambiar el estado de una propiedad que
contiene un tipo Boolean: utilizando el operador Not.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 178


Con el botón btnActivar, cambiamos el valor de la propiedad Enabled del cuadro de texto que
contiene los apellidos. Para ello, aplicamos el operador Not a dicha propiedad, y el resultado
lo asignamos a esa misma propiedad. Ver Código fuente
Private Sub btnActivar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnActivar.Click
' utilizando operador Not simplificamos
Me.txtApellidos.Enabled = Not (Me.txtApellidos.Enabled)
End Sub
Finalizando con este ejemplo, y aunque no tiene relación directa con el control TextBox, el
formulario se muestra con un tipo de borde especial que no permite su redimensión. La
propiedad del formulario con la que podemos establecer el tipo de borde es
FormBorderStyle, y en este caso, su valor es Fixed3D. Alterando los valores de esta
propiedad, conseguiremos distintos bordes y tipos de redimensión para el formulario.

Selección de texto en un TextBox


La selección de texto en un control TextBox es un proceso que funciona de modo
transparente al programador, en el sentido en que este no necesita añadir código
adicional para las operaciones de selección, cortar, copiar, etc., al ser tareas integradas en
el sistema operativo. Sin embargo, podemos necesitar en un determinado momento,
tener información acerca de las operaciones de selección que está realizando el usuario
en nuestros controles de texto. Para ello, el control TextBox dispone de las siguientes
propiedades.
SelectionStart. Posición del texto del control, en la que comienza la selección
que hemos realizado.
SelectionLength. Número de caracteres seleccionados en el control.
SelectedText. Cadena con el texto que hemos seleccionado en el control.
Mediante estas propiedades, no sólo averiguamos la selección que pueda tener un control
TextBox, sino que también podemos utilizarlas para establecer por código una
selección; teniendo el mismo efecto que si la hubiera efectuado el usuario con el ratón o
teclado.
Para comprobar el funcionamiento de las propiedades de selección del TextBox,
crearemos un proyecto Windows, y en su formulario añadiremos varios controles para
manipular la selección de texto que hagamos en un TextBox. La Figura muestra el
formulario del ejemplo.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 179


. Formulario para realizar selección en el control TextBox

El control de este formulario, que vamos a emplear para las operaciones de selección es
txtOrigen. En primer lugar, y aunque no se trata de una selección de texto, veremos su evento
TextChanged, el cual se produce cada vez que cambia el contenido del cuadro de texto; lo
usaremos por tanto, para contar lacantidad de caracteres escritos y mostrarlos en un Label.
Ver Código fuente
' al cambiar el texto del control se produce este evento
Private Sub txtOrigen_TextChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles txtOrigen.TextChanged
' calculamos la longitud del texto escrito
Me.lblContador.Text = Me.txtOrigen.TextLength
End Sub
Los eventos MouseMove y KeyDown del TextBox, se producen respectivamente, cuando
movemos el ratón sobre el control, o cada vez que pulsamos una tecla para escribir texto.
Detectaremos en este caso, si existen teclas o botones especiales presionados, que nos
indiquen que se está realizando unaselección de texto, y mostraremos en el formulario el
texto seleccionado, el número de caracteres y la posición del carácter de inicio de la
selección. Veamos los procedimientos manipuladores de estos eventos en el Código fuente

' al mover el ratón por el TextBox se produce este evento


Private Sub txtOrigen_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles txtOrigen.MouseMove
' comprobamos si al mover el ratón está pulsado su botón izquierdo
' en caso afirmativo es que se está seleccionando texto, por lo que obtenemos la
' información de selección con las ' propiedades de selección del TextBox
If e.Button.Left Then
Me.lblTextoSelec.Text = Me.txtOrigen.SelectedText
Me.lblLongitud.Text = Me.txtOrigen.SelectionLength
Me.lblPosicion.Text = Me.txtOrigen.SelectionStart
End If
End Sub
' este evento se produce cuando se pulsa una tecla en el TextBox
Private Sub txtOrigen_KeyDown(ByVal sender As Object, ByVal e As
System.Windows.Forms.KeyEventArgs) Handles txtOrigen.KeyDown
' comprobamos las teclas pulsadas si está pulsada la tecla mayúsculas, y además
' se está pulsando la tecla flecha derecha, quiere decir que se está seleccionando
' texto ; obtener la información de las propiedades de selección del control TextBox
If e.Shift Then
If e.KeyCode.Right Then
Me.lblTextoSelec.Text = Me.txtOrigen.SelectedText
Me.lblLongitud.Text = Me.txtOrigen.SelectionLength
Me.lblPosicion.Text = Me.txtOrigen.SelectionStart
End If
End If
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 180


Finalmente, tras introducir un valor en los controles txtPosicion y txtLongitud,
pulsaremos el botón btnSeleccionar. Con ello conseguiremos realizar una selección de
texto en el TextBox txtOrigen, y pasar el texto seleccionado al control txtDestino. El
efecto será el mismo que si lo hubiera realizado el usuario, pero en este caso sin su
intervención. Veamos en el Código fuente, el evento Click del botón btnSeleccionar.

' al pulsar este botón, seleccionar por código texto del control txtOrigen y
' pasarlo al control txtDestino
Private Sub btnSeleccionar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnSeleccionar.Click
Me.txtOrigen.SelectionStart = Me.txtPosicion.Text
Me.txtOrigen.SelectionLength = Me.txtLongitud.Text
Me.txtDestino.Text = Me.txtOrigen.SelectedText
End Sub
La Figura muestra este ejemplo en ejecución.

Pruebas de selección de texto con el control TextBox

5.2.4.-Control Button

Este control representa un botón de pulsación, conocido en versiones anteriores de


VB como CommandButton. Entre el nutrido conjunto de propiedades de este
control, destacaremos las siguientes.

Propiedades

Este control también tiene propiedades similares al control Label, entre aquéllas
propiedades exclusivas y nuevas de esta versión, tenemos:
Propiedad
Descripción
Cursor Permite modificar el cursor del ratón que por defecto tiene el botón.
Font Cambia el tipo de letra y todas las características del tipo
Name elegido, para e l t ex t o del boton
Generalmente usaremos el prefijo btn.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 181


BackgroundImag Especifica la imagen de fondo que usará el botón.
e
DialogResult Determina el valor del formulario padre si se da clic sobre el
botón.

FlatStyle Determina el estilo o apariencia del control. Tiene 3 valores.

Image Imagen que se mostrará en el control.

ImageAlign Alineación de la imagen dentro del control. Tiene 9 opciones.


Text Cadena con el título del botón.
TextAlign. Alineación o disposición del título dentro del área del botón; por
defecto aparece centrado.

Métodos

Método
Descripción
NotifyDefault Indica si el botón será el control por defecto. Es de tipo lógico.

PerformClick Ejecuta el evento clic del botón.

Eventos

Evento
Descripción
Click Se desencadena al dar clic con el mouse sobre la etiqueta.

GotFocus Ocurre al ingresar el foco sobre el botón.

LostFocus Ocurre al salir el foco del botón.

MouseEnter Se habilita al ingresar el mouse sobre el botón.

MouseLeave Se habilita al salir el mouse del botón.

MouseMove Se desencadena al pasar el mouse sobre el botón.

La Figura muestra un ejemplo de control Button, sobre el que se han modificado algunos
valores por defecto de sus propiedades.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 182


5.2.5.-Control ListBox

Un control ListBox contiene una lista de valores, de los cuales, el usuario puede
seleccionar uno o varios simultáneamente. Entre las principales propiedades de este
control, podemos resaltar las siguientes.
Items. Contiene la lista de valores que visualiza el control. Se trata de
un tipo ListBox.ObjectCollection, de manera que el contenido de la lista puede ser
tanto tipos carácter, como numéricos y objetos de distintas clases. Al seleccionar esta
propiedad en la ventana de propiedades del control, y pulsar el botón que contiene,
podemos introducir en una ventana elementos para el control. Ver Figura

Introducción de valores para un ListBox en tiempo de diseño.


El control quedaría por lo tanto con valores asignados en la etapa de diseño, como
muestra la Figura

ListBox en diseño con valores en su lista.


Sorted. Cuando esta propiedad contiene el valor True, ordena el contenido de la lista.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 183


Cuando contiene False, los elementos que hubiera previamente ordenados, permanecen
con dicho orden, mientras que los nuevos no serán ordenados.
IntegralHeight. Los valores de la lista son mostrados al completo cuando esta propiedad
contiene True. Sin embargo, al asignar el valor False, según el tamaño del control, puede
que el último valor de la lista se visualiza sólo en parte. La Figura 253 muestra un ListBox
con esta propiedad a False.

ListBox mostrando parte del último elemento debido a la propiedad IntegralHeight.

Propiedades

Propiedad
Descripción
Name Generalmente usaremos el prefijo lst.

ColumnWidth Indica el ancho de cada columna en una lista de varias


columnas.

HorizontalExtent Indica el ancho mínimo en píxeles que se requiere para que


aparezca la barra horizontal.

HorizontalScrollbar Muestra u oculta la barra de desplazamiento horizontal de la


lista.

IntegralHeight Determina que las opciones de la lista se vean en forma


completa.

ItemHeight Devuelve el alto en píxeles de cada elemento de la lista.

Items Es la principal propiedad y se refiere a los elementos de la lista.

MultiColumn Indica si los elementos se pueden ver en varias columnas.

ScrollAlwaysVisible Visualiza siempre las 2 barras de desplazamiento.

SelectionMode Determina la forma de selección que puede ser: None


(ninguno), One (uno), MultiSimple (varios con click) y
MultiExtended (varios con shift + click o ctrl + click).

Sorted Ordena la lista en forma ascendente.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 184


SelectedIndex Devuelve o establece el índice del elemento seleccionado.

SelectedItem Devuelve el ítem seleccionado de la lista.

Métodos

Método
Descripción
FindString Devuelve el índice de un elemento buscado en una lista. Si no
existe devuelve -1 y si existe devuelve un número mayor que -1.

FindStringExact Realiza una labor similar al método anterior pero compara con
exactitud la cadena.

GetSelected Devuelve true si un elemento ha sido seleccionado o false si no.

InsertItem Inserta un elemento en una cierta posición de la lista.

Eventos

Evento
Descripción
DoubleClick Ocurre al dar dos veces clic sobre la lista.

SelectedIndexChange Ocurre al cambiar el índice del elemento seleccionado.


d

Colección Items

Para trabajar con los elementos de una lista se hace uso de la colección Items, la
cual se detalla a continuación:

Propiedades

Propiedad
Descripción
All Devuelve un objeto con todos los elementos de la lista.

Count Devuelve el número de elementos de la lista.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 185


Métodos

Método
Descripción
Add Añade un elemento al final de la lista.

Clear Borra todos los elementos de la lista.

Insert Inserta un elemento en la posición indicada por el índice.

Remove Elimina un elemento de la lista de acuerdo a su índice.

En resumen:

listBox1.Items.Add(dato): Inserta un elemento al final del listbox.

listBox1.Items.Clear(): Elimina todos los elementos de la lista.

listBox1. Items.Count(): Regresa la cantidad de elementos en lista.

listBox1. Items.Sorted = true; Ordena los elementos de la lista usada solo al tiempo de
diseno.

listBox1.Items.Contains(dato): Regresa true o false, si el dato se encuentra o no se

encuentra en la lista.

listBox1. Items.IndexOf(dato): Regresa el indice del objeto dentro del listbox.

listBox1.Items.Insert(indice,dato): Inserta el dato en la posicion indicada.

listBox1.Items.Remove(dato): Elimina el dato de el listbox.

listBox1. Items.RemoveAt(indice): Elimina el dato que esta en la posicion indicada.

listBox1.Items[indice]: get or set el dato en la posicion indicada

Para mostrar algunas de las funcionalidades de este control, utilizaremos el proyecto


de ejemplo ListBoxPru. La Figura muestra esta aplicación en ejecución.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 186


Ejemplo de uso del control ListBox.
El ejemplo, como puede comprobar el lector, consiste en un formulario que contiene
un ListBox principal, con el nombre lstValores, que dispone de una serie de valores
asignados en tiempo de diseño.
Cada vez que hacemos clic en alguno de los valores, se produce el evento
SelectedIndexChanged, que utilizamos para mostrar en este caso, el nombre del elemento en
el título del formulario, como muestra el Código fuente, de la clase frmListas, correspondiente
al formulario.
' declaramos esta constante a nivel de clase, para poner como título
' del formulario junto al elemento seleccionado de la lista
Public Const TITULO As String = "Elemento seleccionado: "
' este evento se produce cada vez que se cambia el índice seleccionado del ListBox

Private Sub lstValores_SelectedIndexChanged(ByVal sender As System.Object,


ByVal e As System.EventArgs) Handles lstValores.SelectedIndexChanged
' mostrar en el título del formulario el valor actualmente seleccionado de la lista
Me.Text = TITULO & Me.lstValores.SelectedItem
End Sub

A través de los RadioButton, cambiamos el tipo de selección que podemos efectuar en


el control lstValores. Ver Código fuente

Private Sub rbtUno_CheckedChanged(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles rbtUno.CheckedChanged
' establecer tipo de selección en el ListBox a un elemento
Me.lstValores.SelectionMode = SelectionMode.One
End Sub

Private Sub rbtMultiple_CheckedChanged(ByVal sender As System.Object, ByVal e


As System.EventArgs) Handles rbtMultiple.CheckedChanged
' establecer tipo de selección en el ListBox a un múltiples elementos
Me.lstValores.SelectionMode = SelectionMode.MultiSimple
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 187


Private Sub rbtExtendida_CheckedChanged(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles rbtExtendida.CheckedChanged
' establecer tipo de selección en el ListBox a múltiples
' elementos de modo extendido
Me.lstValores.SelectionMode = SelectionMode.MultiExtended
End Sub

Mediante los controles chkOrdenar y chkColumnas, ordenaremos y mostraremos en


columnas respectivamente el ListBox. Ver Código fuente.

Private Sub chkOrdenar_CheckedChanged(ByVal sender As System.Object, ByVal e


As, System.EventArgs) Handles chkOrdenar.CheckedChanged
' según el valor del CheckBox, ordenamos o quitamos
' la opción de ordenar del ListBox
Me.lstValores.Sorted = Me.chkOrdenar.Checked
End Sub

Private Sub chkColumnas_CheckedChanged(ByVal sender As System.Object, ByVal


e As System.EventArgs) Handles chkColumnas.CheckedChanged
' según el valor del CheckBox, mostramos el ListBox
' en varias columnas o en una
Me.lstValores.MultiColumn = Me.chkColumnas.Checked
End Sub

El TextBox de este formulario lo usaremos para añadir nuevos elementos al ListBox


lstValores, y buscar también elementos existentes, pulsando los botones btnAgregar y
btnBuscar en cada caso. Observemos el miembro NoMatches del ListBox, mediante el
que averiguamos si la búsqueda tuvo éxito. Ver el Código fuente

Private Sub btnAgregar_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnAgregar.Click
' añadimos el contenido del TextBox como un elemento a la lista
Me.lstValores.Items.Add(Me.txtValor.Text)
End Sub

Private Sub btnBuscar_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnBuscar.Click
Dim iPosicion As Integer
' el método FindString() de la lista busca un valor
iPosicion = Me.lstValores.FindString(Me.txtValor.Text)
' el campo NoMatches indica si no existe el valor buscado
If iPosicion = Me.lstValores.NoMatches Then
MessageBox.Show("No existe el valor")
Else
' si encontramos el valor en la lista,lo seleccionamos por código
Me.lstValores.SelectedIndex = iPosicion
End If

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 188


End Sub

La selección de los elementos de un ListBox no es competencia exclusiva del usuario. El


programador puede también, si lo necesita, seleccionar valores de la lista mediante el
código del programa. Al pulsar el botón btnSelecCod, utilizaremos el método SetSelected(
) del ListBox para realizar esta tarea.

En este método pasamos como parámetro el índice de la lista con el que vamos a operar,
y el valor True para seleccionarlo, o False para quitarle la selección. Ver el Código fuente
Private Sub btnSelecCod_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnSelecCod.Click
' para seleccionar elementos de un ListBox por código
' podemos utilizar el método SetSelected()
Me.rbtMultiple.Checked = True
Me.lstValores.SetSelected(1, True)
Me.lstValores.SetSelected(3, True)
Me.lstValores.SetSelected(5, True)
End Sub

El botón btnTraspasarSelec lo usaremos para tomar los elementos seleccionados de


lstValores, y pasarlos al otro ListBox del formulario. La propiedad SelectedItems del
control lstValores, devuelve una colección con sus elementos seleccionados. Por otra
parte, podemos eliminar los elementos de un ListBox llamando al método Clear( ) de
la colección de valores del control, cosa que hacemos pulsando el botón btnLimpiar.
Ver Código fuente

Private Sub btnTrapasarSelec_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnTrapasarSelec.Click
Dim oSeleccion As ListBox.SelectedObjectCollection
' obtenemos con SelectedItems los elementos seleccionados de un ListBox
oSeleccion = Me.lstValores.SelectedItems
' si existen elementos seleccionados, los traspasamos a otro ListBox del
' formulario
If oSeleccion.Count > 0 Then
Dim oEnumerador As IEnumerator
oEnumerador = oSeleccion.GetEnumerator()
While oEnumerador.MoveNext()
Me.lstTraspaso.Items.Add(oEnumerador.Current)
End While
End If
End Sub

Private Sub btnLimpiar_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnLimpiar.Click
' con el método Clear() de la colección de elementos
' de un ListBox, borramos los elementos del controls
Me.lstTraspaso.Items.Clear()

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 189


End Sub

Ejemplo programa

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles Button1.Click
LISTA.Items.Add(DATO.Text)
DATO.Text = ""
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles Button2.Click

Dim r, cant, meses As Integer


cant = LISTA.Items.Count

For r = 0 To cant - 1
meses = LISTA.Items(r)
meses = meses * 12
LISTA.Items(r) = meses
Next r
End Sub

Recordar que el primer indice en un ListBox es el cero por eso el ciclo va desde el cero hasta
la cantidad de elementos menos uno.

Corrida:

Actividades de reforzamiento de lo aprendido

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 190


EJERCICIOS PROGRAMACION DE LISTBOX

1.- Capturar en una lista los sueldos de 6 empleados y desplegarlos en una segunda lista
aumentados en un 30%

2.- Capturar en una lista los pesos en kilogramos de 6 personas desplegarlos en una segunda
lista convertidos a libras y ademas solo los mayores de 100 libras.

3.- Capturar en sus 4 listas respectivas matricula, nombre y dos calificaciones de 5 alumnos,
despues calcular una lista de promedios de calificaciones.

4.- Capturar en sus listas respectivas numempleado, nomempleado, dias trabajados y sueldo
diario de 5 empleados, desplegar en otra pantalla o panel la nomina pero solo de aquellos
empleados que ganan mas de $300.00 a la semana.

5.2.6.-Control ComboBox

El ComboBox es un control basado en la combinación (de ahí su nombre) de dos


controles que ya hemos tratado: TextBox y ListBox.
Un control ComboBox dispone de una zona de edición de texto y una lista de valores,
que podemos desplegar desde el cuadro de edición.
El estilo de visualización por defecto de este control, muestra el cuadro de texto y la
lista oculta, aunque mediante la propiedad DropDownStyle podemos cambiar dicho estilo.
La Figura muestra un formulario con diversos ComboBox, cada uno con diferente estilo.

Controles ComboBox de distintos estilos.

La propiedad DropDownStyle también influye en una diferencia importante de


comportamiento entre el estilo DropDownList y los demás, dado que cuando creamos un
ComboBox con el mencionado estilo, el cuadro de texto sólo podrá mostrar información, no
permitiendo que esta sea modificada.
En el caso de que la lista desplegable sea muy grande, mediante la propiedad
MaxDropDownItems, asignaremos el número de elementos máximo que mostrará la lista del
control.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 191


El resto de propiedades y métodos son comunes con los controles TextBox y ListBox.
En el Código fuente se muestra el código del botón btnAgregar, mediante el que
llenamos de valores los controles de este ejemplo.
Private Sub btnAgregar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnAgregar.Click
Me.cboColores.Items.AddRange(New String() {"AZUL", "VERDE", "AMARILLO",
"ROJO", "BLANCO", "MARRÓN", "GRANATE"})
Me.cboNombres.Items.AddRange(New String() {"ELENA", "JOSE", "ANA",
"ALFREDO", "LUIS", "ANGEL", "RAQUEL"})
Me.cboCiudades.Items.AddRange(New String() {"SEVILLA", "VALENCIA",
"ALICANTE", "TOLEDO", "SEGOVIA"})
End Sub

Propiedades de ComboBox

Propiedad
Descripción
Name Generalmente usaremos el prefijo cbo.

Items Es la principal propiedad y se refiere a los elementos del


combo.

MaxDropDownItem Indica el máximo número de elementos que se mostrarán al


s desplegarse el combo.

MaxLenght Determina el máximo número de caracteres que se podrán


escribir en el cuadro de texto del combo.

Sorted Ordena los elementos del combo en forma ascendente.

Style Especifica el tipo de combo que puede ser: Simple, DropDown


(por defecto), y DropDownList.

SelectedIndex Devuelve o establece el índice del elemento seleccionado.

SelectedItem Devuelve el ítem seleccionado de la lista.

SelectedText Devuelve el texto seleccionado de la lista.

Text Se refiere al texto escrito en el cuadro del combo.

Métodos

Método
Descripción

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 192


FindString Devuelve el índice de un elemento buscado en el combo. Si no
existe devuelve -1 y si existe devuelve un número mayor que -1.

FindStringExact Realiza una labor similar al método anterior pero compara con
exactitud la cadena.

Eventos

Evento
Descripción
Click Ocurre al dar clic con el mouse a un elemento de la lista.

DoubleClick Se da al dar dos veces clic sobre un elemento de la lista.

SelectedIndexChanged Ocurre al cambiar el índice del elemento seleccionado.

SelectionChangeCommi Se da cuando se selecciona un elemento del combo.


ted
TextChanged Ocurre al cambiar la propiedad Text del combo.

Colección Items

La colección Items del combo es similar a la del ListBox.

Propiedades

Propiedad
Descripción
All Devuelve un objeto con todos los elementos del combo.

Count Devuelve el número de elementos del combo.

Métodos

Método
Descripción
Add Añade un elemento al final del combo.

Clear Borra todos los elementos del combo.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 193


Insert Inserta un elemento en la posición indicada por el índice.

Remove Elimina un elemento del combo de acuerdo a su índice.

Ejemplo de del uso de ComboBox(). Ahora empecemos creando un nuevo proyecto de


Visual Basic. Necesitamos las siguientes herramientas: 2 LABEL, 2 TEXEDIT, 3
BOTONES y un COMBOBO Cuando arrastres estos componentes, trate de que tu
formulario tenga este aspecto

Primero aprenderemos a insertar un nuevo ítem, hacemos doble clic en el botón INSERTAR

Ahora en medio de la función BUTTON1_CLICK antes de END SUB escribimos el


siguiente código que sirve para agregar nuevos ítems a nuestro componente COMBOBOX1
Private sub ButtonAgregar.Click…..
'primero verificamos que en TEXBOX2 no esté vacio
If TextBox2.Text.Length > 0 Then
ComboBox1.Items.Add(TextBox2.Text) 'adicionamos el item de COMBOX
End If
End Sub

Para editar un ítem de nuestra herramienta COMBOBOX1, hacemos doble clic en el botón
EDITAR, el siguiente código sirve para editar un ítem
Private sub ButtonEditar.Click…..
'primero verificamos que TEXBOX1 y TEXBOX2 no estén vacío
If TextBox1.Text.Length > 0 And TextBox1.Text.Length > 0 Then
' eliminamos el ítem de la posición TEXBOX1
ComboBox1.Items.RemoveAt (CInt(TextBox1.Text))
' inserta el Nuevo elemento TEXBOX2
ComboBox1.Items.Insert (CInt(TextBox1.Text), TextBox2.Text)
End if
End sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 194


Ahora volvemos al formulario y esta vez hacemos doble clic en el botón3 que es el botón
eliminar, Para eliminar un ítem de la herramienta COMBOBOX escribimos el siguiente
código en la función de nuestro botón Eliminar:
Private sub ButtonEliminar.Click…..
'primero verificamos que TEXBOX1 no este vacío
If TextBox1.Text.Length > 0 And TextBox1.Text.Length > 0 Then
' eliminamos el ítem de la posición TEXBOX1
ComboBox1.Items.RemoveAt (CInt(TextBox1.Text))
End if
End Sub

Este otro ejemplo siguiente muestra como ingresar una fecha considerando edades entre 17
y 90 años. El botón Comprobar permite mostrar un mensaje si la fecha seleccionada es
Correcta o Incorrecta.

A continuación sigue código en Visual Basic

Private Sub Cargar(ByVal sender As System.Object, ByVal e As System.EventArgs) Han


dles MyBase.Load
'Llenar el Día
Dim i As Integer
For i = 1 To 31
cboDia.Items.Add(i)
Next
'Llenar los Nombres de los Meses
For i = 1 To 12
cboMes.Items.Add(MonthName(i, False))
Next
'Al ingresar el rango para los años existen diferentes posibilidades...
‘consideremos mayores de 18 años hasta las 90 años
For i = Year(Now) - 90 To Year(Now) - 17
cboAnio.Items.Add(i)
Next
End Sub

Private Sub CompruebaFecha(ByVal sender As System.Object, ByVal e As System.Eve


ntArgs) Handles cmdComprobar.Click
If cboDia.SelectedIndex = -1 Or cboMes.SelectedIndex = -1 Or _
cboAnio.SelectedIndex = -1 Then
MessageBox.Show("Faltan datos...", "Fecha incompleta",
MessageBoxButtons.OK)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 195


Exit Sub
End If
Dim vfecha As String
vfecha = Trim(cboDia.SelectedItem) & "/" & Trim(Str(cboMes.SelectedIndex + 1))
& "/" & Trim(cboAnio.SelectedItem)
If Microsoft.VisualBasic.IsDate(vfecha) = False Then
MessageBox.Show("Fecha no valida...", "Error de ingreso",
MessageBoxButtons.OK)
Else
MessageBox.Show("Fecha CORRECTA...", "Dato Válido",
MessageBoxButtons.OK)
End If
End Sub

5.2.7.-Control CheckBox

Este control muestra una casilla de verificación, que podemos marcar para establecer un
estado. Generalmente el estado de un CheckBox es marcado (verdadero) o desmarcado
(falso), sin embargo, podemos configurar el control para que sea detectado un tercer
estado, que se denomina indeterminado, en el cual, el control se muestra con la marca
en la casilla pero en un color de tono gris.
Las propiedades remarcables de este control son las siguientes.

Propiedades

Propiedad
Descripción
Name Generalmente usaremos el prefijo chk.

Appearance Controla la apariencia del control, puede ser: Normal (como


casilla) o Button (como botón de comando).

AutoCheck Cambia de estado cada vez que se da clic al botón.

CheckAlign Controla la alineación del checkbox. Hay 9 posiciones.

Checked Indica si el checkbox ha sido seleccionado o no.

CheckState Devuelve el estado del checkbox, que puede ser: Unchecked (sin
marcar), Checked (marcado) o Indeterminate (gris).

ThreeState Habilita o deshabilita el estado indeterminado del checkbox cada


vez que se da el tercer clic.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 196


Métodos

Método
Descripción
Focus Pone el foco sobre el checkbox.

Hide Oculta el checkbox, sin descargarlo de la memoria.

Show Pone visible el checkbox.

Eventos

Evento
Descripción
CheckedChanged Ocurre al cambiar el valor de la propiedad Checked del control.

CheckStateChange Ocurre al cambiar el valor de la propiedad CheckState del


d control.

Observacion:
Como detalle destacable de las propiedades Checked y CheckState, si modificamos desde
código sus valores, conseguiremos alterar el estado de la casilla del control.
El ejemplo CheckBoxPru, muestra un formulario con dos controles CheckBox.
El control chkPonColor asigna un color de fondo al formulario o restablece el
color original. Esto lo conseguimos codificando el evento CheckedChanged del control.
Ver Código fuente.
' Este evento se produce cuando se hace clic en el CheckBox y cambia el contenido
' de la casilla
Private Sub chkPonColor_CheckedChanged(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles chkPonColor.CheckedChanged
If Me.chkPonColor.CheckState = CheckState.Checked Then
Me.BackColor = Color.LightBlue
Else
Me.ResetBackColor()
End If
End Sub

Por su parte, el control chkMostrar, definido con tres estados, muestra, al estar marcado,
una cadena en un control Label; elimina la cadena al desmarcarlo; y muestra la mitad
al entrar en el estado indeterminado. El evento CheckStateChanged es el que debemos de
utilizar para detectar el estado del CheckBox en cada ocasión. Para mantener el valor de la
cadena a mostrar, utilizamos una variable a nivel de la clase que inicializamos en el
constructor del formulario. Ver Código fuente

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 197


Public Class Form1
Inherits System.Windows.Forms.Form
Private sCadenaOriginal As String
Public Sub New()
'....
' inicializar la variable que contiene la cadena
' a mostrar en el label y asignarla
sCadenaOriginal = "Estamos visualizando una cadena"
Me.lblMuestra.Text = sCadenaOriginal
End Sub
'....
' este evento se produce cuando cambia el estado de la casilla
Private Sub chkMostrar_CheckStateChanged(ByVal sender As Object, ByVal e As
System.EventArgs) Handles chkMostrar.CheckStateChanged
Select Case Me.chkMostrar.CheckState
Case CheckState.Checked
Me.lblMuestra.Text = sCadenaOriginal
Case CheckState.Unchecked
Me.lblMuestra.Text = ""
Case CheckState.Indeterminate
Me.lblMuestra.Text = sCadenaOriginal.Substring(0,(sCadenaOriginal.Length / 2))
End Select
End Sub

La Figura muestra este ejemplo en ejecución.

Controles CheckBox en ejecución.

5.2.8. Control CheckedListBox

Es un nuevo control que antes se obtenía configurando la propiedad style del control
Listbox a checked. Como es similar al control ListBox solo mencionaremos las
características distintas que tiene el control CheckedListBox.

Propiedades

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 198


Propiedad
Descripción
Name Generalmente usaremos el prefijo ckl.

CheckOnClick Establece si el control podrá ser fijado la primera vez al dar click.

ThreeDCheckBox Indica si la apariencia de los items se mostrará en 3D o plano.

Métodos

Método
Descripción
GetItemChecked Devuelve true si un cierto item ha sido seleccionado o false si no.

GetItemCheckState Devuelve el valor de la propiedad CheckState de un cierto item.

SetItemChecked Establece o quita la selección de un cierto elemento.

SetItemCheckState Establece la propiedad CheckState de un cierto elemento.

Eventos

Evento
Descripción
ItemCheck Ocurre al seleccionar un elemento y poner el check en true.

SelectedIndexChange Ocurre al seleccionar otro elemento.


d

5.2.9.-Control RadioButton

Antes conocido como OptionButton, es un control en el que solo se puede


seleccionar uno por contenedor. Los controles RadioButton nos permiten definir
conjuntos de opciones autoexcluyentes, de modo que situando varios controles de este tipo
en un formulario, sólo podremos tener seleccionado uno en cada ocasión.

Propiedades

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 199


Propiedad
Descripción
Name Generalmente usaremos el prefijo rbn.

Appearance Controla la apariencia del control, puede ser: Normal (como


botón de opción) o Button (como botón de comando).

AutoCheck Cambia de estado cada vez que se da clic al botón.

CheckAlign Controla la alineación del botón. Hay 9 posiciones.

Checked Indica si el botón ha sido seleccionado o no.

Métodos

Método
Descripción
Focus Pone el foco sobre el radiobutton.

Hide Oculta el radiobutton, sin descargarlo de la memoria.

Show Pone visible el radiobutton.

Eventos

Evento
Descripción
CheckedChange Ocurre al cambiar la propiedad checked del radiobutton.
d
Click Se desencadena al dar clic con el mouse sobre el botón.

DoubleClick Se desencadena al dar doble clic con el mouse sobre el botón.

5.2.10-Control GroupBox

Antes conocido como Frame, es un contenedor que se utiliza para agrupar varias opciones,
que pueden ser: de opción única como los RadioButton o de opción múltiple como los
CheckBox.
Este control se utiliza como contenedor y por si solo no tiene mucha funcionalidad, es por
eso, que solo veremos sus principales propiedades, métodos y eventos.

Propiedades

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 200


Propiedad
Descripción
Name Generalmente usaremos el prefijo gbx.

Enabled Determina si el control estará habilitado o deshabilitado.

Text Indica el texto que se mostrará como encabezado del control.

Visible Muestra u oculta al control y todo su contenido.

Métodos

Método
Descripción
Focus Pone el foco sobre el control.

Hide Oculta el control, sin descargarlo de la memoria.

Show Pone visible el cuadro de grupo.

Eventos

Evento
Descripción
GotFocus Ocurre al ingresar el foco sobre el control.

LostFocus Ocurre al salir el foco del control.

Vamos a crear un proyecto de ejemplo con el nombre RadioButtonPru, en el que situaremos


dentro de un formulario, una serie de controles RadioButton y un TextBox, de modo
que mediante los RadioButton cambiaremos el tipo de fuente y color del cuadro de texto.
La Figura muestra un diseño inicial del formulario.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 201


Pruebas con el control RadioButton.
Al ejecutar el proyecto, sin embargo, no podemos conseguir establecer simultáneamente
un tipo de letra y color, puesto que al pulsar cualquiera de los botones de radio, se
quita el que hubiera seleccionado previamente.
Para solucionar este problema, disponemos del control GroupBox, que nos permite, como
indica su nombre, agrupar controles en su interior, tanto RadioButton como de otro tipo, ya
que se trata de un control contenedor.
Una vez dibujado un GroupBox sobre un formulario, podemos arrastrar y soltar sobre él,
controles ya existentes en el formulario, o crear nuevos controles dentro de dicho control. De
esta forma, podremos ya, en este ejemplo, seleccionar más de un RadioButton del formulario,
como vemos en la Figura .

Selección de varios RadioButton en un formulario.


El evento CheckedChanged, al igual que ocurría con los controles CheckBox, será el que
tendremos que escribir para ejecutar el código en respuesta a la pulsación sobre un
control RadioButton. El Código fuente muestra los eventos correspondientes a los
controles de radio de este ejemplo. Para cambiar el tipo de fuente, instanciamos un
objeto Font y lo asignamos a la propiedad Font del TextBox; mientras que para cambiar
el color, utilizamos la estructura Color y la propiedad BackColor, también del TextBox.
Private Sub rbtTahoma_CheckedChanged(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles rbtTahoma.CheckedChanged
Me.txtNombre.Font = New Font("Tahoma", 12)
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 202


Private Sub rbtGaramond_CheckedChanged(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles rbtGaramond.CheckedChanged
Me.txtNombre.Font = New Font("Garamond", 8)
End Sub

Private Sub rbtComic_CheckedChanged(ByVal sender As System.Object, ByVal e


As System.EventArgs) Handles rbtComic.CheckedChanged
Me.txtNombre.Font = New Font("Comic Sans MS", 15)
End Sub

Private Sub rbtVerde_CheckedChanged(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles rbtVerde.CheckedChanged
Me.txtNombre.BackColor = Color.Green
End Sub

Private Sub rbtAzul_CheckedChanged(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles rbtAzul.CheckedChanged
Me.txtNombre.BackColor = Color.Blue
End Sub
Private Sub rbtAmarillo_CheckedChanged(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles rbtAmarillo.CheckedChanged
Me.txtNombre.BackColor = Color.Yellow
End Sub

5.2.11.- Controles VScrollBar, HScrollBar, TrackBar

Un control VScrollBar es una barra de desplazamiento que permite manipular rangos


de valores numéricos por medio de su propiedad Value, los cuales son establecidos por las
propiedades maximum (máximo valor) y minimum (mínimo valor). El control
HScrollBar realiza la misma función, sólo se diferencia en su forma de presentación.
Estos controles son utilizados para implementar el desplazamiento en los contenedores que
no proporcionan sus propias barras de desplazamiento, como PictureBox.

El objeto TrackBar es un control desplazable similar al control ScrollBar.


Para configurar los intervalos entre los que se desplaza el valor de la propiedad Value de
una barra de seguimiento, estableciendo la propiedad Minimum para especificar el extremo
inferior del intervalo y la propiedad Maximum para especificar el extremo superior del
intervalo.

7.3.1 Ejemplo práctico controles VScrollBar y TrackBar

Realizar una aplicación que permita a un usuario por medio de controles VScrollBar y
TrackBar visualizar un color al realizar un desplazamiento en cualquiera de los controles.

Crear la interfaz de usuario

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 203


Utilizando el cuadro de herramientas haga clic en el control VScrollBar y ubique 3
controles en el formulario en la posición deseada, además, seleccione el control TrackBar
y ubique 3 controles en el formulario. También seleccione el control Label y ubique 7
controles en el formulario. La figura 7.11., muestra la interfaz de usuario.

Establecer las propiedades de los objetos de la interfaz de usuario


Después de colocar los controles u objetos en el formulario, establezca las siguientes
propiedades a los controles:

Tabla 7.3 Propiedades de los controles de la aplicación BarrasdeDesplazamiento.

Nombre del proyecto :


Control Propiedad Valor
VScrollBar1, Name barra1, barra2, barra3
VScrollBar2, Maximum 255
VScrollBar3. Minimum 0
TrackBar1, Name desplazamiento1, desplazamiento2,
TrackBar2, desplazamiento3
TrackBar3 Maximum 255
Minimum 0
Label1 Name txtcolores
Text En blanco
BorderStyle FixedSingle
Label2 Name txttitulo
Text Colores Personalizados
TextAlign MiddleCenter
Font Microsoft Sans Serif, 8pt, style=Bold
Label3 Name txttrackbar
Text Colores con TrackBar
TextAlign MiddleCenter
Label4 Name txtvalores
Text Valores del color
TextAlign MiddleCenter
Label5 Name color1
Text En blanco
Label6 Name color2
Text En blanco
Label7 Name color3

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 204


Text En blanco
Form1 Name formulario
Text Controles VScrollBar y TrackBar

Interfaz de usuario (VScrollBar, TrackBar).

Escribir código

Seleccione el objeto barra1, dé doble clic para abrir el editor del procedimiento
barra1_Scroll y escriba el siguiente código:

txtcolores.BackColor = Color.FromArgb(barra1.Value, barra2.Value, barra3.Value)


color1.Text = "Azul=" & barra3.Value

Seleccione el objeto barra2, dé doble clic para abrir el editor del procedimiento
barra2_Scroll y escriba el siguiente código:

txtcolores.BackColor = Color.FromArgb(barra1.Value, barra2.Value,


barra3.Value) color2.Text = "Verde=" & barra2.Value

Seleccione el objeto barra3, dé doble clic para abrir el editor del procedimiento
barra3_Scroll y escriba el siguiente código:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 205


txtcolores.BackColor = Color.FromArgb(barra1.Value, barra2.Value,
barra3.Value)
color3.Text = "Rojo=" & barra1.Value

Para los controles TrackBar realice la misma programación, solamente es necesario


cambiar el nombre del control es decir barra? por desplazamiento?.

En el anterior código al control txtcolores se le modifica la propiedad Backcolor


asignándole el método FromArgb de la clase Color el cual define un color tomando como
parámetros los valores para rojo, verde y azul y opcionalmente el nivel de transparencia.
Al desplazarse sobre cada control se obtiene un valor el cual se asigna respectivamente a
cada color. Después por cada barra de desplazamiento se le asigna a los objetos Label
(color1, color2, color3) en su propiedad Text el nombre del color y el valor que toma el
control en su propiedad Value. Esta operación se realiza también en el control TrackBar.

Ejecutar el proyecto

Al ejecutar el proyecto en el entorno de desarrollo de visual Basic.NET, se visualiza:

Ejecución aplicación Barras de Desplazamiento.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 206


Al dar realizar el desplazamiento de la barra sobre cada uno de los controles
VScrollBar el fondo del Label deberá ir cambiar de color. Al realizar esta operación se
visualizará la siguiente figura:

Ejecución aplicación Barras de Desplazamiento.

Esto mismo se puede realizar cambiando de posición la barra de seguimiento


(TrackBar) para obtener un color.
5.2.11.-Controles de tipo menú

El menú es uno de los tipos de control más frecuentemente utilizados en los formularios
Windows. Consiste en un conjunto de opciones, a través de las cuales, el usuario ejecutará
algunos procesos de la aplicación. Disponemos de tres tipos de control menú: MainMenu,
ContextMenu y MenuItem.
MainMenu y ContextMenu actúan como contenedores de grupos de controles
MenuItem, representando este último control, la opción de menú sobre la que el usuario pulsa
o hace clic.
El proyecto MenuPru que se acompaña como ejemplo, muestra los diferentes tipos de menú .
A continuación, describiremos los principales pasos a dar en el proceso de su construcción.
Menú Principal. MainMenu
Un control MainMenu, consiste en un conjunto de opciones que se sitúan horizontalmente
debajo del título del formulario. A partir de cada opción, podemos asociar a su vez,
grupos de opciones que se mostraran verticalmente al hacer clic en la opción principal o
situada en la barra horizontal.
Para crear un menú principal, seleccionaremos del cuadro de herramientas el control

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 207


MainMenu, y tras dibujarlo en el formulario, se añadirá una referencia del control al
panel de controles especiales situado bajo el diseñador. La Figura muestra un control
de este tipo al que le hemos dado el nombre mnuPrincipal.

Menú de tipo MainMenu añadido al diseñador del formulario.

La creación de las diferentes opciones que compondrán el menú es un proceso que se ha


mejorado y simplificado al máximo respecto a versiones anteriores de VB. El proceso
de edición del menú se realiza directamente en el formulario, en el mismo lugar en el
que el menú aparecerá en tiempo de ejecución.
Al hacer clic en la primera opción del menú, podemos dar nombre y propiedades a esa
opción. Al mismo tiempo, de un modo muy intuitivo, veremos las próximas opciones
disponibles, tanto las desplegables a partir de dicho menú, como las de la barra principal.
Sólo hemos de movernos en la dirección que necesitemos y dar nombre a las opciones, y
valores a sus propiedades. Ver Figura

Creación de las opciones de un menú principal de formulario.

Cada una de las opciones que componen el menú es a su vez un control MenuItem.
Si durante su creación sólo proporcionamos el nombre, el IDE va asignando a dicho
control valores por defecto en sus propiedades.
Para modificar las propiedades de una opción de menú, sólo hemos de seleccionarlo en la
estructura de menú que estamos creando en el diseñador del formulario, y pasar a la
ventana de propiedades. Entre las propiedades disponibles para un MenuItem, podemos
destacar las siguientes.
Text. Contiene una cadena con el literal o texto descriptivo de la opción de menú.
Enabled. Permite habilitar/deshabilitar la opción de menú. Cuando se encuentra

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 208


deshabilitada, se muestra su nombre en un tono gris, indicando que no puede ser
seleccionada por el usuario.
DefaultItem. Permite establecer opciones por defecto. En una opción de menú por
defecto, su texto se resalta en negrita.
Checked. Marca/desmarca la opción. Cuando una opción está marcada, muestra
junto a su nombre un pequeño símbolo de verificación o punteo.
RadioCheck. En el caso de que la opción de menú se encuentre marcada, si
asignamos True a esta propiedad, en lugar de mostrar el símbolo de verificación
estándar, se muestra uno con forma de punto.
ShortCut. Se trata de un atajo de teclado, o combinación de teclas que nos van
a permitir ejecutar la opción de menú sin tener que desplegarlo. Al elegir esta
propiedad, aparecerá una lista con todos los atajos disponibles para asignar.
ShowShortCut. Permite mostrar u ocultar la combinación de teclas del atajo de
teclado que tenga asignado una opción de menú.
Visible. Muestra u oculta la opción de menú.
MdiList. Esta propiedad se utiliza habitualmente en opciones situadas en la barra
de menú, y permite establecer que dicha opción al desplegarse, muestre, además
de las opciones de menú que le hayamos asignado, la lista de ventanas secundarias
MDI, en el caso de que el menú principal esté contenido en un formulario de
tipo MDI. Los formularios MDI serán tratados posteriormente.
Podemos adicionalmente, asignar una tecla de acceso rápido o hotkey a una opción
de menú, anteponiendo el carácter & a la letra que deseemos, de las que se encuentran en
la propiedad Text del control MenuItem. Al igual que sucede con los demás tipos de
controles, en el texto de la opción de menú, aparecerá subrayada la mencionada letra.
De este modo, cuando despleguemos un menú, no será necesario posicionarnos en una
de ellas para ejecutarla, sino que simplemente pulsando la tecla rápida, se ejecutará el
código de dicha opción.
También podemos establecer separadores entre las opciones de menú simplemente creando
una opción y asignando a su propiedad Text el carácter de guión ( - ).
En nuestro formulario de ejemplo, vamos pues a diseñar un menú con la estructura
del esquema mostrado en la Figura
Para todas las opciones se ha asignado una tecla de acceso rápido, y adicionalmente, para
las opciones que se indican a continuación, se han modificado algunas propiedades por
defecto.
Guardar. Deshabilitada.
Salir. Atajo de teclado en Ctrl. + S.
Copiar. Opción por defecto.
Pegar. Marcada con símbolo normal.
Cortar. Marcada con símbolo de círculo.
Elipse. Opción no visible.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 209


Esquema del menú de ejemplo.
La Figura muestra el formulario en ejecución con una parte del menú abierta.

Menú desplegado a varios niveles, mostrando opciones.


Una vez finalizada la fase de diseño del menú, debemos proceder a escribir el código
para sus opciones. El evento Click es el que permite a un control MenuItem ejecutar código
cuando la opción de menú es seleccionada. Abriendo por tanto, el menú desde el diseñador
del formulario, y haciendo doble clic en la opción correspondiente, nos situaremos en
el editor de código, dentro del procedimiento manipulador del evento Click para esa
opción. El Código fuente muestra el código que se ejecutará cuando seleccionemos las
opciones de menú Abrir y Salir de nuestro ejemplo.
Private Sub mnuAbrir_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuAbrir.Click
MessageBox.Show("Opción Abrir del menú")
End Sub

Private Sub mnuSalir_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuSalir.Click
Me.Close()
End Sub

Puesto que muchas de las propiedades de un control MenuItem son manipulables en


tiempo de ejecución, añadiremos al formulario varios botones, mediante los cuales
realizaremos operaciones sobre las opciones del menú tales como habilitar y deshabilitar,
mostrar y ocultar, cambiar el nombre, etc. La Figura muestra el formulario con estos
nuevos botones.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 210


Controles Button para manipular por código las propiedades de las opciones del menú.
En el Código fuente podemos ver los manipuladores de evento de estos botones.
Private Sub btnHabilitar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnHabilitar.Click
Me.mnuGuardar.Enabled = Not Me.mnuGuardar.Enabled
End Sub

Private Sub btnMarcar_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnMarcar.Click
Me.mnuPegar.Checked = Not Me.mnuPegar.Checked
End Sub

Private Sub btnMostrar_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnMostrar.Click
Me.mnuElipse.Visible = Not Me.mnuElipse.Visible
End Sub

Private Sub btnNombre_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnNombre.Click
If Me.mnuAbrir.Text = "A&brir" Then
Me.mnuAbrir.Text = "HO&LA"
Else
Me.mnuAbrir.Text = "A&brir"
End If
End Sub

Private Sub btnDefecto_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnDefecto.Click
Me.mnuCopiar.DefaultItem = Not Me.mnuCopiar.DefaultItem
End Sub

Menú Contextual. ContextMenu


El control ContextMenu representa un menú contextual o flotante. Este tipo de menú se
asocia al formulario o a uno de sus controles, de modo que al hacer clic derecho, se mostrará
sobre el elemento al que se haya asociado.
El modo de añadir un control ContextMenu y sus correspondientes opciones al
formulario, es el mismo que para un MainMenu; situándose también una referencia del

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 211


menú contextual en el panel de controles especiales del diseñador. Antes de poder diseñar
las opciones de un ContextMenu, debemos pulsar la referencia de dicho menú que existe
en el panel de controles especiales, ya que por defecto, el formulario muestra el menú
principal en caso de que tenga uno definido.
La Figura muestra el menú contextual mnuContexto, que hemos añadido al
formulario. Para asociar este menú con un control o formulario, utilizaremos la
propiedad ContextMenu de que disponen la mayoría de los controles Windows. En este
ejemplo, insertaremos el control txtValor, de tipo TextBox, y le asociaremos el menú de
contexto que acabamos de crear.

Como resultado, cuando ejecutemos la aplicación, al hacer clic derecho sobre el TextBox,
aparecerá el menú contextual que hemos asignado, mediante el que cambiaremos el tipo
de fuente de la caja de texto, transformaremos el texto a mayúsculas y minúsculas. El
Código fuente muestra el código de los eventos Click correspondiente a las opciones del
menú contextual.
Private Sub mnuFuente_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuFuente.Click
Dim oFuente As New Font("Comic", 15)
Me.txtValor.Font = oFuente
End Sub

Private Sub mnuMayusculas_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuMayusculas.Click
Me.txtValor.Text = Me.txtValor.Text.ToUpper()
End Sub

Private Sub mnuMinusculas_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuMinusculas.Click
Me.txtValor.Text = Me.txtValor.Text.ToLower()
End Sub

La Figura muestra el aspecto del menú contextual, cuando es utilizado desde el control
TextBox.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 212


Control ContextMenu asociado a un TextBox.

5.3.-Foco de entrada
Para que las pulsaciones de teclado puedan ser recibidas por un determinado control, dicho
control debe tener lo que se denomina el foco de entrada.
El modo de dar a un control el foco de entrada, consiste en hacer clic sobre él, o bien, pulsar
la tecla [TAB], pasando el foco hasta el control deseado. Cuando un control recibe el
foco, el sistema operativo lo remarca visualmente o en el caso de controles de escritura,
muestra el cursor de escritura en su interior.
Otra forma es realizar la codificación del foco de entrada, de la siguiente manera
Private Sub btnActivar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnActivar.Click
' utilizando la propiedad focus para el control textbox1
Textbox1.focus
End Sub
5.4.-Programacion de los eventos de controles
Windows es un sistema operativo orientado a eventos, por lo que cualquier mínima
interacción que realicemos sobre un formulario o control, generará el oportuno evento,
para el que si estamos interesados, deberemos responder.
Prosiguiendo con el control Button, cuando pulsamos sobre el mismo, se origina el
evento Click de dicho control. Si dibujamos un Button en un formulario y pulsamos en
él, no ocurrirá nada, ya que aunque el evento se produce, no existe código que le
proporcione respuesta.
Para dar oportuna respuesta a un evento emitido por un control, debemos escribir un
procedimiento manipulador del correspondiente evento. La creación de manipuladores de
evento es un aspecto que ya hemos visto en detalle en el tema Delegación de código y
eventos. De igual modo, los aspectos básicos de la escritura de código para un evento se
comentaron en el tema Una aplicación con funcionalidad básica; sugerimos por lo tanto
al lector, la consulta de estos temas para cualquier referencia básica que necesite al
respecto.
No obstante, en el presente apartado, y para reforzar conceptos, realizaremos un repaso del
proceso de creación del manipulador de evento para un control.
Como ejemplo, insertaremos en un formulario un control Button, al que daremos el
nombre btnMensaje, y en su propiedad Text asignaremos la cadena Mostrar mensaje.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 213


Seguidamente haremos doble clic sobre el Button; esta acción abrirá la ventana del editor
de código, creando al mismo tiempo, la declaración o esqueleto del procedimiento
manipulador de evento Click del botón, listo para ser codificado.
Ya que necesitamos que se muestre un mensaje al ser pulsado este control, utilizaremos
el objeto MessageBox de la plataforma, llamando a su método compartido Show( ), para
visualizar el mensaje. En definitiva, el manipulador de este evento quedaría como muestra el
Código fuente
Private Sub btnMensaje_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnMensaje.Click
MessageBox.Show("Se acaba de pulsar el botón del formulario")
End Sub
El resultado en ejecución, sería el que muestra la Figura

Observando con más detalle el procedimiento del evento, vemos que al final de su
declaración, aparece la palabra clave Handles, que como vimos en el tema sobre eventos,
nos sirve para asociar esta rutina de código con un evento de un objeto. En el
ejemplo que nos ocupa, asociamos el procedimiento btnMensaje_Click( ), con el
evento Click del objeto btnMensaje, perteneciente a la clase Button.

Resultado de la ejecución del evento Click de un control Button, al ser pulsado.


Como ya sabemos, el enlace procedimiento-evento de objeto mediante la palabra Handles,
se producede modo estático. Esto requiere que en el código, el identificador que contenga
el objeto del control, deba ser declarado con ámbito a nivel de clase, y utilizando además
la palabra clave WithEvents.
Dicha tarea es realizada automáticamente por el diseñador del formulario cuando genera el
código del mismo. Veamos en el Código fuente , el fragmento de código generado por
el diseñador que realiza esta labor.
' esta declaración es situada a nivel del código de la clase del formulario, es decir,
' fuera de cualquier método
Friend WithEvents btnMensaje As System.Windows.Forms.Button

5.5.-Programando otros eventos de un control


En un control Button, el evento por defecto es Click; esto supone, como acabamos de ver,
que al hacer doble clic sobre el control en el formulario, el procedimiento de evento
sobre el que nos situará el editor será precisamente este. Sin embargo, un control Button,
al igual que el resto de controles de los formularios Windows, disponen de un gran número

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 214


de eventos que podemos codificar para adaptar a nuestras necesidades.
Por ejemplo, el evento MouseEnter, se produce cuando se detecta que el ratón entra en
el área de un control, en este caso Button. Como este no es el evento por defecto,
debemos buscar su declaración vacía manualmente en el editor. Para ello, abriremos la
lista desplegable Nombre de clase, situada en la parte superior izquierda del editor de
código, y seleccionaremos el nombre de nuestro control: btnMensaje. Ver Figura

Lista de clases del editor de código.


A continuación, abriremos la otra lista desplegable del editor de código: Nombre de método,
situada en la parte superior derecha del editor. En ella aparecerán los nombres de
todos los eventos de que dispone el control. Localizaremos el evento MouseEnter, y lo
seleccionaremos. Ver Figura

Lista de eventos de una clase-control en el editor de código.


De igual modo que sucedió con el evento Click en el apartado anterior, el editor de
código creará el procedimiento manipulador de evento vacío, para el evento que
acabamos de seleccionar. Lo que vamos a hacer a continuación, es escribir el código
que permita cambiar el color del botón cuando el ratón entre al mismo. Veamos el Código
fuente
Private Sub btnMensaje_MouseEnter(ByVal sender As Object, ByVal e As
System.EventArgs) Handles btnMensaje.MouseEnter
Me.btnMensaje.BackColor = Color.Cyan
End Sub

Cuando al ejecutar, situemos el ratón en el botón, este cambiará su color, mostrando el


aspecto de la Figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 215


Resultado de la ejecución del evento MouseEnter sobre un Button.

5.6.-Orden de tabulación de controles


Los controles disponen de la propiedad TabIndex, que contiene un número que será
utilizado para pasar el foco entre ellos al pulsar la tecla [TAB] durante la ejecución del
programa. Según vamos añadiendo nuevos controles, el IDE va asignando automáticamente
nuevos números a esta propiedad; de forma que, cuando comencemos la ejecución, el primer
control que tomará el foco será el que tiene el menor número en su TabIndex.
En el ejemplo anterior, el primer control que tomaba el foco era el TextBox de la contraseña,
lo cual no era nada lógico, ya que dicho control era el último en el formulario para el que
debíamos introducir datos.
Para solucionar este problema, simplemente tenemos que cambiar los valores de la
propiedad TabIndex de los controles, de modo que el orden de tabulación sea el que mejor
se adapte a nuestras necesidades.
Podemos obtener un mapa del orden de tabulación de los controles del formulario
seleccionando el menú del IDE Ver + Orden de tabulación; esto mostrará los controles con
el número de TabIndex que les hemos asignado. Como ventaja adicional, en esa situación,
podemos hacer clic en los controles y cambiar también el número de tabulación. Ver Figura

Diseñador del formulario mostrando el orden de tabulación de controles.


Si por el contrario, no queremos dar el foco a un control pulsando [TAB], debemos
asignar a la propiedad TabStop de dicho control el valor False. Por defecto, TabStop
vale True, permitiendo de esta el paso de foco entre controles mediante la tecla [TAB].

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 216


5.7.-Funciones para presentar mensajes
Visual Basic posee 2 tipos de funciones para presentar mensajes, ellas son MsgBox e
InputBox.

5.7.1.-Función InputBox:

La función InputBox presenta un mensaje al usuario, permitiéndole ingresar un valor en


una caja de texto:

Como se dijo la función InputBox presenta un cuadro de diálogo donde el usuario puede
ingresar un texto y luego aceptar o cancelar dicho cuadro de diálogo.

Los parámetros principales de esta función son:

InputBox (Promt,Title, Default)

 El parámetro Prompt específica la leyenda que mostrará la caja de mensajes.


 El parámetro Title especifica el título que llevará el cuadro de diálogo.
 El parámetro Default es el texto que mostrará la caja de texto.

El aspecto más importante de InputBox es que nos devuelve una cadena con lo que haya
ingresado el usuario en la caja de texto. Luego podemos realizar una tarea específica
dependiendo del valor devuelto.

Ejemplo:

Dim retorno As String


retorno = InputBox("Ingrese algo en la caja de texto", "Ejemplo")
MsgBox "Usted ingresó:" & retorno

En el ejemplo anterior, en la variable Retorno se almacenará el valor que haya ingresado el


usuario cuando haga Click en el botón de Aceptar.

Cuando el usuario presiona Candelar, el InputBox devuelve una cadena vacía. Esto es
importante tenerlo en cuenta para realizar una o tal acción

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 217


Si quiseramos por ejemplo desplegar un InputBox, y que este no se cierre hasta que el usuario
si o si haya ingresado un valor, podemos hacerlo de la siguiente forma, utilizando una
condición en un bucle Do Loop

Código fuente en el formulario

Private Sub Form_Load()


Dim Dato As String
'Hasta que no se ingrese un dato, el InputBox no se cerrará
Do
Dato = InputBox("Ingresar algun dato", " Ejemplo ")
Loop Until Dato <> ""
'Muestra el valor
MsgBox Dato, vbInformation
End Sub

5.7.2.-Función MsgBox:
La función MsgBox, es muy fácil de usar y se utiliza para mostrar distintos tipos de
mensajes. La sintaxis completa de la función MsgBox es:

MsgBox(mensaje[, botones][, título][, archivoAyuda, contexto])

Ejemplos de mensajes o cajas de texto con la función MsgBox que podemos mostrar:

Como se ve en los gráficos anteriores, con MsgBox podemos tener variedad a la hora de
mostrar un determinado mensaje, utilizando para ello las diferentes constantes que
incorpora la función.

Los parámetros más importantes son:


 Title : Es la leyenda que aparecerá en el título del mensaje.
 Texto : Es el Texto que mostrará el mensaje.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 218


 Botones: En este parámetro se colocan las constantes que determinarán si la caja tiene
uno o varios botones y el tipo de mensaje: informativo, de exclamación de alerta etc...
Cuando escribimos la coma dentro de la función en el parámetro botones, Visual
Basic despliega una lista con las opciones o constantes que podemos utilizar.

Ejemplo de msgbox un poco más elaborado para entender un poco mejor esto; este ejemplo
envía un mensaje de alerta con dos botones como opciones: En vez de utilizarse las palabras
mensaje, estilo, etc se podrían utilizar otras, pero siempre hay que respetar el orden
Private Sub Command1_Click()
Dim Mensaje, Estilo, Título, Respuesta, MiCadena as String
Mensaje = "¿Estas totalmente seguro de lo que vas a hacer?"
' cuerpo del mensaje.
Estilo = vbYesNo + vbCritical
' Define el estilo, los botones, lo que está después del mas es el circulo rojo '
con la cruz.
Título = "error grave (mentira)" ' es el título.
Respuesta = MsgBox(Mensaje, Estilo, Título)
'el paréntesis se pone también
If Respuesta = vbYes Then ' El usuario eligió el botón Sí.
MiCadena = "Sí" ' Ejecuta una acción.
Else ' El usuario eligió el botón No.
MiCadena = "No" ' Ejecuta una acción.
Form1.Visible = False 'Aca puse una acción que usted ya conoce
End If
End Sub
En estilo podrían ir por ejemplo las siguientes opciones:

VbOKOnly: Sólo muestra el botón Aceptar.


VbOKCancel: Muestra los botones Aceptar y Cancelar.
VbAbortRetryIgnore: Muestra los botones Anular, Reintentar e
Ignorar.
VbYesNoCancel: Muestra los botones Sí, No y Cancelar.
VbYesNo: Muestra los botones Sí y No.
VbRetryCancel: Muestra los botones Reintentar y Cancelar.
VbCritical: Muestra el icono Mensaje crítico.
VbQuestion: Muestra el icono Consulta de advertencia.
VbExclamation: Muestra el icono Mensaje de advertencia.
VbInformation: Muestra el icono Mensaje de información.
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 219
5.8.- Controles avanzados de Visual Basic
5.8.1.-Control Temporizadores (Timer)
En VB.NET disponemos al igual que en anteriores versiones, del control Timer, que nos
permite la ejecución de código a intervalos de tiempo predeterminados.

Este control ha sufrido una importante reestructuración, ya que internamente hace uso
de la clase Timer, perteneciente al conjunto de clases del sistema. El hecho de poder
acceder a esta clase, nos proporciona una gran flexibilidad en nuestros desarrollos, ya que,
a partir de ahora también crearemos temporizadores por código, sin necesidad de utilizar
el control Timer.

Ejemplo de reloj digital


Vamos a mostrar una forma simple y sencilla de crear en visual basic .net un reloj digital.
Lo haremos utilizando un label y un componente Timer.

El formulario debería tener una apariencia similar a la de la siguiente imagen>

Para este ejemplo donde solo mostraremos la hora, cambiaremos la fuente del control label
para darle más importancia. Yo estoy usando fuente Tahoma tamaño 28.

Ahora veamos las propiedades del componente timer. Para que se ejecute el codigo del evento
Tick del componente timer, este tiene que tener la propiedad enable en True. Y el codigo que
ingresemos se va a ejecutar cada n ticks. La cantidad de ticks de n se las indicamos con la

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 220


propiedad interval en milisegundo. Por lo tanto si colocamos dicha propiedad en 1000 ticks,
el código se ejecutará cada 1 segundo.

Ahora veamos el código, es muy sencillo:

Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As


System.EventArgs) Handles Timer1.Tick

Label1.text =Date.now.TolongTimeString

End sub

Solo resta ejecutar (F5) la aplicación y tendremos nuestro reloj digital como se muestra en
la siguiente imagen>

Otro ejemplo
En el ejemplo TimerPru que comentamos a continuación, vamos a construir un formulario
en el que utilizaremos los dos tipos de temporizadores, el propio control Timer y un objeto
de la clase. El primer proceso a codificar, consistirá en traspasar a intervalos de
tiempo, el contenido de un TextBox del formulario, a otro control de este mismo tipo. El
formulario del proyecto se muestra en la Figura

Figura Formulario para ejemplo con temporizadores.


Tras incluir los controles de usuario en el formulario, añadiremos un control Timer, al que
daremos el nombre tmrTemporizador. Esta acción abrirá, bajo el diseñador del formulario,
un panel para controles especiales, como es el caso de Timer, en el que se mostrará dicho
control.
En este panel se depositan los controles del formulario que no tienen una interacción
directa con el usuario, o cuyo diseño es diferente al de los controles habituales.
Para especificar el espacio de tiempo en el que este control será ejecutado cuando lo

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 221


activemos, utilizaremos la propiedad Interval, a la que tenemos que asignar un valor
numérico, que establece dicho tiempo en milisegundos. En nuestro caso, asignaremos
500, con lo que el control se ejecutará cada medio segundo.

Panel para controles especiales del diseñador de formularios.


El control Timer lo activaremos llamando a su método Start( ), cosa que hacemos al
pulsar el botón btnTraspasar.
Private Sub btnTraspasar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnTraspasar.Click
' iniciar el temporizador
Me.tmrTemporizador.Start()
End Sub

Una vez activado un temporizador, cada vez que transcurre el tiempo indicado en Interval,
genera un evento Tick. Es precisamente en este evento en el que debemos escribir el código
que necesitamos que se ejecute a intervalos regulares de tiempo. Haremos, por consiguiente,
doble clic en el control Timer del diseñador, para acceder al procedimiento manipulador de
este evento, cuyo contenido lo podemos ver

' Este evento se produce en el intervalo especificado en el control Timer


Private Sub tmrTemporizador_Tick(ByVal sender As Object, ByVal e As
System.EventArgs) Handles tmrTemporizador.Tick
' quitamos una letra del TextBox de origen...
Dim sLetra As String
sLetra = Me.txtOrigen.Text.Substring(0, 1)
Me.txtOrigen.Text = Me.txtOrigen.Text.Remove(0, 1)
' ...y lo pasamos al TextBox de destino
Me.txtDestino.Text &= sLetra
' cuando se haya traspaso todo el texto detener el temporizador
If Me.txtOrigen.Text.Length = 0 Then
Me.tmrTemporizador.Stop()
MessageBox.Show("Traspaso finalizado")
End If
End Sub

5.8.2.-Control ImageList
Este control actúa como repositorio de imágenes, del que se alimentarán otros controles del

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 222


formulario que necesiten mostrar gráficos en su interior.
Una vez añadido este control en el formulario, se situará en el panel de controles
especiales del diseñador, y haciendo clic en su propiedad Images, se abrirá la ventana
de la Figura, en la que podremos añadir y quitar las imágenes que van a formar parte de
la lista del control, así como ver en el panel complementario, la información sobre cada
imagen asignada.

Ventana de administración de imágenes del control ImageList.

Las imágenes que insertamos en el control tienen un tamaño por defecto, en el


caso de que necesitemos modificarlo, expandiremos la propiedad ImageSize en la
ventana de propiedades y asignaremos nuevos valores en Width y Height.
Otra ventaja de este control es que nos permite manipular las imágenes por código, por
ejemplo, para añadir nuevas imágenes, debemos usar el método Add( ) de su propiedad
Images, como muestra el Código fuente
Me.imlImagenes.Images.Add(New Bitmap("tutorias.gif"))

5.8.3.-Control ToolBar
Este control representa la barra de herramientas o botones de acceso rápido que facilitan
al usuario la ejecución de los procesos principales del programa, evitándole la
navegación por el menú del formulario.
Al ser dibujado, este control queda acoplado a la parte superior del formulario. Después
de ponerle tbrBarra como nombre, asignaremos a su propiedad ImageList, el control
de ese mismo tipo que acabamos de crear; esto nos permitirá asignar los gráficos de
la lista a los botones que vayamos creando en el ToolBar. Para establecer el tamaño de
los botones de la barra utilizaremos la propiedad ButtonSize de este control.
Seguidamente haremos clic en la propiedad Buttons, que abrirá una ventana con la
colección de botones de la barra, en la que podremos crear y configurar dichos botones.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 223


Editor de botones del control ToolBar.
Cada botón en un ToolBar es un objeto de tipo ToolBarButton, del que podemos
destacar las siguientes propiedades.
Text. Cadena con el texto que muestra el botón.
ImageIndex. En el caso de asociar el ToolBar con un control ImageList, en esta
propiedad asignamos para un botón una de las imágenes del ImageList, indicando el
número de orden de la imagen.
Style. Permite establecer el estilo del botón: de pulsación; separador; o de tipo
desplegable, que abre un subconjunto de opciones.
DropDownMenu. Si asociamos el botón con una opción de la barra de menú del
formulario, y configuramos su estilo como DropDownButton, al pulsar el botón
desplegable, se mostrarán las opciones de menú; el efecto será el mismo que si
hubiéramos desplegado directamente el menú del formulario.
La Figura muestra la ventana principal de la aplicación con la barra de herramientas

Formulario con ToolBar.


Una vez terminado el diseño del ToolBar, debemos codificar su evento ButtonClick,
que será provocado cada vez que se pulse un botón de la barra. Dentro del
procedimiento de este evento, comprobaremos qué botón ha sido pulsado y ejecutaremos
las acciones oportunas.
Tanto el botón Abrir como la opción de menú del mismo nombre realizan la misma tarea,
por lo que llaman al método AbrirArchivo( ), que es quien realmente muestra el

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 224


formulario necesario.
Private Sub tbrBarra_ButtonClick(ByVal sender As System.Object, ByVal e As
System.Windows.Forms.ToolBarButtonClickEventArgs) Handles
tbrBarra.ButtonClick
' comprobar qué botón de la barra se ha pulsado
If e.Button Is Me.btnAbrir Then
' llamamos al método que abre el formulario para abrir un archivo
Me.AbrirArchivo()
End If
If e.Button Is Me.btnSalir Then
' cerrar la aplicación
Me.Close()
End If
End Sub
Private Sub mnuAbrir_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuAbrir.Click
' al seleccionar esta opción de menú llamar al método que
' abre el formulario que permite abrir un archivo
Me.AbrirArchivo()
End Sub

Private Sub AbrirArchivo()


Dim ofrmAbrirArchivo As New frmAbrirArchivo()
ofrmAbrirArchivo.MdiParent = Me
ofrmAbrirArchivo.Show()
End Sub

Al haber asignado al botón btnPersonal uno de los menús de la barra del formulario, no
será necesario escribir código para detectar este botón en el evento ButtonClick, ya que
se ejecutará directamente el código del evento Click de las opciones de menú. El
Código fuente 523 muestra el código perteneciente a la opción de menú Personal +
Datos.

Private Sub mnuDatos_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuDatos.Click
Dim ofrmPersonal As New frmDatosPersonal()
ofrmPersonal.MdiParent = Me
ofrmPersonal.Show()
End Sub

5.8.4.-Control StatusBar
Para mostrar una barra informativa de estado recurriremos a este control, que al
dibujarse queda situado en la parte inferior del formulario; como nombre le daremos
sbrEstado. De forma similar al ToolBar, un control StatusBar está compuesto de una
colección de objetos Panel, que iremos añadiendo al control mediante la propiedad
Panels, la cual mostrará una ventana para la creación y configuración de tales paneles.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 225


Editor de paneles del control StatusBar.
Entre las propiedades destacables de un objeto Panel podemos mencionar las siguientes.
BorderStyle. Muestra el panel con efecto resaltado, hundido o normal.
Icon. Permite asociar un icono al panel.
AutoSize. Con esta propiedad podemos conseguir que el panel se redimensione
ajustándose a su contenido o que tenga un tamaño fijo.
En este ejemplo, hemos añadido dos paneles a la barra de estado del formulario. En uno
mostramos un texto fijo; mientras que en el otro, visualizamos la hora actual a través
de un objeto Timer que ponemos en marcha en el evento Load del formulario. Veamos
los métodos implicados, en el Código fuente 524.
Private Sub frmPrincipal_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles MyBase.Load
' al cargar el formulario, creamos un temporizador
' le asociamos un manejador para su evento Tick y lo iniciamos
Dim oTiempo As New Timer()
oTiempo.Interval = 1000
AddHandler oTiempo.Tick, AddressOf PonerHoraActual
oTiempo.Start()
End Sub

Private Sub PonerHoraActual(ByVal sender As Object, ByVal e As EventArgs)


' actualizamos a cada segundo la hora de un panel de la barra de estado
Me.sbrEstado.Panels(1).Text = DateTime.Now.ToString("HH:mm:ss")
End Sub

La Figura muestra el formulario con la barra de estado.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 226


Formulario con StatusBar.
Finalizada la creación del StatusBar, añadiremos al proyecto un formulario con
el nombre frmDatosPersonal, en el dibujaremos un conjunto de nuevos controles que
iremos describiendo seguidamente.
5.8.5.-Control DateTimePicker
Este control permite la selección e introducción de fechas en una caja de texto con
capacidades extendidas, o bien mediante un calendario desplegable que se mostrará al
pulsar el botón de expansión que contiene. Ver Figura

Control DateTimePicker.
Para modificar la fecha en el cuadro de texto, debemos situarnos en la parte a modificar de
la fecha y teclear el nuevo valor, o bien, con las flechas de dirección arriba-abajo, cambiar
esa parte de la fecha. Si expandimos el calendario, podremos realizar la selección de un
modo más gráfico.
Por defecto el control muestra la fecha actual, pero con la propiedad Text podemos
cambiar la fecha por código, cosa que hacemos al cargar el formulario, asignando una
fecha distinta de la actual. Ver Código.
Private Sub frmDatosPersonal_Load(ByVal sender As Object, ByVal e As
System.EventArgs) Handles MyBase.Load
' modificar fecha del DateTimePicker
Me.dtpFNacim.Text = "15/06/2002"
'....
End Sub

Podemos restringir el rango de fechas a mostrar por este control con las propiedades

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 227


MinDate y MaxDate. Si queremos, por otra parte, que la fecha se muestre con un
formato personalizado, aplicaremos dicho formato mediante la propiedad CustomFormat,
teniendo en cuenta que no se hará efectivo hasta que a la propiedad Format no le
asignemos el valor Custom.

El botón btnCambiosFecha del formulario realiza algunas modificaciones por código sobre
el control DateTimePicker dtpFNacim del formulario, que vemos en el Código
Private Sub btnCambiosFecha_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnCambiosFecha.Click
' configurar por código el control DateTimePicker
Me.dtpFNacim.MinDate = "1/4/2002"
Me.dtpFNacim.MaxDate = "1/10/2002"
Me.dtpFNacim.CustomFormat = "d-MMM-yy"
Me.dtpFNacim.Format = DateTimePickerFormat.Custom
End Sub

5.8.6.-Control NumericUpDown
Control que muestra una caja de texto con un valor numérico que podremos ir
aumentando- disminuyendo al pulsar los botones para esta labor de que dispone el control.
La Figura muestra este control en nuestro formulario de pruebas.

Control NumericUpDown.
Entre las propiedades de este control destacaremos las siguientes.
Increment. Número en el que se incrementará el valor del control cuando
pulsemos sus botones o teclas de dirección.
InterceptArrowKeys. Permite que las flechas de dirección arriba-abajo tengan
el mismo efecto que si pulsamos los botones para incrementar o disminuir, de este
control.
Maximum, Minimun. Contienen los límites superior e inferior en cuanto al
número que podrá contener el control.
TextAlign. Permite alinear el número dentro la caja de texto del control.
UpDownAlign. Permite situar los botones del control a la izquierda o derecha de
la caja de texto que contiene el valor.
Entre los eventos de que dispone este control, ValueChanged se produce cada vez que
cambia el valor del control, de modo que en este caso, vamos a cambiar el color de fondo
en función del número que contenga.
Private Sub nupEdad_ValueChanged(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles nupEdad.ValueChanged
Select Case Me.nupEdad.Value
Case 20 To 30
Me.nupEdad.BackColor = Color.Gold
Case 30 To 40
Me.nupEdad.BackColor = Color.LimeGreen
Case Else
Me.nupEdad.BackColor = Me.nupEdad.DefaultBackColor

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 228


End Select
End Sub

5.8.7.-Control DomainUpDown
Este control nos permite desplazarnos por una lista de valores, al mismo estilo que el control
anterior. Dicha lista de valores la crearemos mediante la propiedad Items, en tiempo de
diseño o ejecución. El Código muestra como al cargar el formulario frmDatosPersonal,
con la propiedad Items y su método AddRange( ), añadimos los valores que
seleccionaremos en el control en tiempo de ejecución.

Private Sub frmDatosPersonal_Load(ByVal sender As Object, ByVal e As


System.EventArgs) Handles MyBase.Load
'....
' crear la lista del DomainUpDown
Me.dudCategoria.Items.AddRange(New String() {"Auxiliar", "Jefe
departamento","Coordinador"})
End Sub

La Figura muestra el control dudCategoría, de este tipo al ser utilizado en el formulario.


En el caso de que necesitemos los valores ordenados, asignaremos True a su propiedad
Sorted.

Control DomainUpDown.
5.8.8.-Control MonthCalendar
Este control muestra en modo gráfico un calendario por el que podemos desplazarnos para
seleccionar una fecha. El control DateTimePicker utiliza internamente un
MonthCalendar para mostrar su calendario desplegable.
Por defecto se visualiza un mes, pero si asignamos a su propiedad CalendarDimensions un
objeto Size, podemos expandir el tamaño del calendario para que muestre varios meses.
El Código muestra el código de un botón del formulario mediante el que cambiamos el
tamaño del calendario.
Private Sub btnTamCalendario_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnTamCalendario.Click
Me.mclCalendario.CalendarDimensions = New Size(2, 2)
End Sub
En la Figura vemos el resultado de expandir el tamaño del control.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 229


Control MonthCalendar con el tamaño ampliado.
Para detectar la selección de una fecha utilizaremos el evento DateChanged. Debido
a que en un control MonthCalendar podemos seleccionar un rango de fechas, las
propiedades que tenemos que manipularpara averiguar la
fechas seleccionadas son: SelectionStart, SelectionEnd y SelectionRange, aunque en
muchas ocasiones sólo será necesario utilizar una de ellas.

Private Sub mclCalendario_DateChanged(ByVal sender As System.Object, ByVal e


As System.Windows.Forms.DateRangeEventArgs) Handles
mclCalendario.DateChanged
' mostrar en un Label la fecha seleccionada en el control MonthCalendar
Me.lblCalendario.Text = Me.mclCalendario.SelectionStart
End Sub
5.8.9.-Control LinkLabel
Este control permite tener en un formulario Windows un enlace hacia una página de Internet,
con un comportamiento similar al que encontramos en un hiperenlace de una página web.
Su propiedad Text muestra un literal, de modo que al hacer clic sobre el mismo, se
provocará el evento LinkClicked en el que escribiremos el código a ejecutar.
En nuestro formulario de ejemplo, hemos creado un control de este tipo con el nombre
lnkEidos, que tiene el aspecto de la Figura 322, ya que además del enlace, le hemos asignado
una imagen.

Control LinkLabel.
Para conseguir que al hacer clic en este enlace, se abra Internet Explorer y navegue
hacia una determinada página, vamos a utilizar la clase Process, que como su nombre
indica, nos permite la gestión de procesos del sistema, tales como su inicio y finalización.
En este caso, el método compartido Start( ), de Process, va a ejecutar el navegador al
pasarle como parámetro una dirección web en forma de cadena. Veamos el Código
Private Sub lnkEidos_LinkClicked(ByVal sender As System.Object, ByVal e As

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 230


System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles
lnkEidos.LinkClicked
' inicia Internet Explorer y navega hacia una página
Process.Start("http://www.eidos.es")
End Sub

Creación y manipulación de elementos en ejecución


El conjunto de controles que acabamos de ver, al igual que los básicos permiten ser
creados no sólo mediante el diseñador de formularios, sino también desde código. Como
muestra de ello, la opción de menú Varios + Añadir botón y panel, añade dos imágenes
al control ImageList del formulario frmPrincipal, creando un nuevo botón para el
ToolBar y un panel para el StatusBar Ver el Código
Private Sub mnuAgregaElementos(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuAgregar.Click
' añadir por código imágenes a la lista
Me.imlImagenes.Images.Add(New Bitmap("tutorias.gif"))
Me.imlImagenes.Images.Add(New Bitmap("camera1.gif"))
Dim oBoton As New ToolBarButton()
oBoton.Text = "TUTORIAS"
oBoton.ImageIndex = 4
Me.tbrBarra.Buttons.Add(oBoton)
Dim oPanel As New StatusBarPanel()
oPanel.Text = "BUSCAR"
oPanel.BorderStyle = StatusBarPanelBorderStyle.Raised
oPanel.ToolTipText = "Información sobre búsquedas"
oPanel.Icon = New Icon("magnify.ico")
Me.sbrEstado.Panels.Add(oPanel)
End Sub

Para detectar la pulsación del nuevo botón de la barra de herramientas, añadimos el


siguiente código en su evento ButtonClick, que vemos en el Código

Private Sub tbrBarra_ButtonClick(ByVal sender As System.Object, ByVal e As


System.Windows.Forms.ToolBarButtonClickEventArgs) Handles
tbrBarra.ButtonClick
'....
If e.Button.Text = "TUTORIAS" Then
MessageBox.Show("Se ha pulsado el botón de tutorías")
End If
End Sub

La Figura muestra este formulario en ejecución tras añadir los nuevos elementos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 231


Nuevos controles añadidos al formulario en tiempo de ejecución.
5.8.10.-Control NotifyIcon
Este control permite añadir un icono asociado con nuestra aplicación en el panel de iconos
del sistema (Windows System Tray) situado en la parte derecha de la barra de tareas de
Windows. Tales iconos suelen utilizarse por aplicaciones que permanecen ocultas, y al
hacer clic derecho sobre su icono en este panel, aparece un menú contextual que permite
mostrar la aplicación.
En nuestro caso vamos a utilizar este control para ejecutar y parar la calculadora
del sistema empleando la clase Process, comentada en un apartado anterior.
Después de agregar un control de este tipo al formulario, asignaremos un icono a su
propiedad Icon y una cadena a su propiedad Text, que será mostrada al situar el ratón encima
de este control en tiempo de ejecución.
Crearemos después un menú contextual con las opciones Abrir y Cerrar, que
asignaremos a la propiedad ContextMenu del control NotifyIcon.
Para poder controlar la calculadora de Windows cuando esté en ejecución, declararemos una
variable de tipo Process a nivel de la clase. Al ejecutar la calculadora mediante el método
Start( ) de la clase Process, obtendremos un objeto de dicho tipo, que pasaremos a esta
variable, y nos permitirá posteriormente, cerrar el proceso en el que se está ejecutando la
calculadora mediante el método Kill( ). Veamos esta parte en el Código
Public Class frmPrincipal
Inherits System.Windows.Forms.Form
Private oCalculadora As Process
'....
Private Sub mnuCalcAbrir_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuCalcAbrir.Click
' iniciar la calculadora
oCalculadora = Process.Start("calc.exe")
End Sub

Private Sub mnuCalcCerrar_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuCalcCerrar.Click
' cerrar la calculadora
oCalculadora.Kill()
End Sub
End Class
Al ejecutar el programa, se mostrará un nuevo icono en la lista del panel de iconos del
sistema de la barra de tareas, como muestra la Figura 324.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 232


Control NotifyIcon en el panel de iconos del sistema de la barra de tareas.

Como se puede comprobar, la clase Process amplía enormemente nuestra capacidad


de manipulación de los procesos del sistema.

5.8.11.-Controles de Diálogos

Controles OpenFileDialog

y SaveFileDialog

Estos controles se usan para facilitar el trabajo con archivos, el primero se refiere al
diálogo de “Abrir Archivo” y el segundo al diálogo “Guardar Archivo”, que en la
versión anterior estaban disponibles como Controles ActiveX.
Ambos tienen características similares que detallamos a continuación:

Propiedades

Propiedad
Descripción
Name Para el OpenFileDialog generalmente usaremos el prefijo odg.
Para el SaveFileDialog generalmente usaremos el prefijo sdg.

AddExtension Añade automáticamente la extensión al nombre del archivo.

CheckFileExits Chequea que exista el archivo antes de regresar del diálogo.

CheckPathExits Chequea que exista la ruta del archivo antes de regresar del
diálogo.

CreatePrompt Solo para el diálogo de Guardar. Si la propiedad ValidateName es


true pide confirmación al usuario cuando el archivo es creado.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 233


DefaultEx Indica la extensión por defecto del archivo.

FileName Indica el archivo escrito o seleccionado del diálogo.

Filter Especifica el tipo de archivo que se mostrará en el diálogo.

FilterIndex Determina el índice del filtro del diálogo. Este empieza en 1 y


depende de la lista de tipos de archivos configurada por Filter.

InitialDirectory Muestra un cierto directorio inicial para los archivos del diálogo.

Multiselect Solo para el diálogo de Abrir. Determina si se pueden seleccionar


varios archivos a la hora de abrir.

OverwritePrompt Solo para el diálogo de Guardar. Si la propiedad ValidateName es


true pide confirmación al usuario cuando un archivo creado existe.

ReadOnlyChecke Solo para el diálogo de Abrir. Determina el estado del checkbox


d ReadOnly en el diálogo de abrir.

RestoreDirectory Controla si el diálogo restaura el directorio actual antes de


cerrarse.

ShowHelp Visualiza o no el botón de Ayuda en el diálogo.

ShowReadOnly Solo para el diálogo de Abrir. Determina si se muestra o no el


checkbox ReadOnly en el diálogo de abrir.

Tile Indica el título a mostrarse en la barra de título del diálogo.

ValidateNames Controla que el nombre del archivo no tenga caracteres inválidos.

Métodos

Método
Descripción
OpenFile Devuelve un Stream indicando el archivo abierto en el diálogo de
abrir o grabado en el diálogo de guardar.

ShowDialog Muestra el diálogo de archivo, sea de abrir o de guardar.

Eventos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 234


Evento
Descripción
FileOk Ocurre al dar clic sobre el botón OK del diálogo de archivo.

5.8.12.-Control FontDialog

Este control se usa para mostrar el diálogo de fuente y poder acceder a sus
características como tipo de fuente, tamaños, estilos, efectos, etc.

Propiedades

Propiedad
Descripción
Name Generalmente usaremos el prefijo fdg.

AllowScriptChang Controla si el conjunto de caracteres de fuente puede ser


e cambiado.

Color Devuelve el color de fuente seleccionado en el diálogo.

Font Determina la fuente seleccionada en el diálogo. Es un objeto.

FontMustExist Indica si se mostrará un reporte de error al no existir una fuente.

MaxSize Máximo tamaño de la fuente en puntos.

MinSize Mínimo tamaño de la fuente en puntos.

ScriptsOnly Controla si excluirá los caracteres OEM y símbolos.

ShowApply Determina si se verá el botón de Aplicar en el diálogo.

ShowColor Indica si se mostrará el color elegido del diálogo.

ShowEffects Muestra el cuadro de efectos que trae: subrayado, tachado y


color.

ShowHelp Visualiza o no el botón de Ayuda en el diálogo.

Métodos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 235


Método
Descripción
ShowDialog Muestra el diálogo de fuente.

Eventos

Evento
Descripción
Apply Ocurre al dar clic sobre el botón de aplicar del diálogo de fuente.

5.8.13.-Control ColorDialog

Este control se usa para mostrar el diálogo de colores y poder acceder a sus
características como seleccionar un color sólido o personalizado.

Propiedades

Propiedad
Descripción
Name Generalmente usaremos el prefijo cdg.

AllowFullOpen Habilita o no el botón de personalizar colores.

AnyColor Controla si cualquier color puede ser seleccionado.

Color Indica el color seleccionado en el diálogo.

FullOpen Determina si la sección de colores personalizados será


inicialmente vista.

ShowHelp Visualiza o no el botón de Ayuda en el diálogo.

SolidColorOnly Controla si solo los colores sólidos pueden ser seleccionados.

Métodos

Método
Descripción
ShowDialog Muestra el diálogo de colores.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 236


Eventos

Evento
Descripción
HelpRequested Ocurre al dar clic sobre el botón de ayuda del diálogo de color.

5.9- Interfaces

Introducción

Una interface es el medio de comunicación entre 2 entidades, en nuestro caso, la


interface sirve de enlace entre el usuario y la aplicación.
En la evolución de la computación se inicia con interfaces de texto o de consola, las
cuales predominan desde los inicios de la computación hasta casi la mitad de la
década del 80, luego aparecen las interfaces gráficas.

Desde que trabajamos en ambiente Windows, las interfaces han ido evolucionando
de acuerdo a la facilidad del usuario para acceder a los elementos de la aplicación,
y entre las principales interfaces tenemos:
 SDI (Single Document Interface): Interface de Simple Documento, muestra una
sola ventana con un cierto documento en la aplicación; el acceso a las ventanas
es secuencial, por lo que no es tan recomendable. Algunas aplicaciones con SDI
son los accesorios de Windows: Bloc de notas, Paint, Wordpad, etc.

 MDI (Multiple Document Interface): Interface de Múltiples Documentos,


muestra varios documentos en sus respectivas ventanas, las cuales aparecen
sobre una ventana principal; el acceso a las ventanas es directo porque
generalmente en la ventana padre existe un menú. Algunas aplicaciones con
MDI son los programas de Office: Word y Excel.

 TreeView - ListView (Vistas Árbol – Lista): Muestra los elementos de la


aplicación en un árbol (TreeView) y en el lado derecho muestra una lista con los
detalles (ListView); puede mostrarse junto a un SDI como en el caso del
Explorador de archivos de Windows o puede mostrarse junto a un SDI como en
el caso del Enterprise Manager de SQL Server 6 o superior.

Con la evolución de Internet también se distinguen diferentes tipos de interfaces en


el browser, pero que no se tocan en este capítulo, si no que nos centraremos en la
creación de interfaces para aplicaciones Windows.

5.10.-Creando Aplicaciones MDI

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 237


Una aplicación MDI consta de 2 partes: un Formulario MDI Padre y uno o mas
Formularios MDI Hijos, la creación de ambos es muy sencilla en VB .NET y se
explica a continuación:

Creando un Formulario MDI Padre

Para crear un Formulario MDI padre solo hay que configurar la propiedad
IsMDIContainer del formulario a True.
A diferencia de la versión anterior de Visual Basic, esta versión permite colocar
cualquier control WinForm dentro del formulario MDI, pero esto hará que los
formularios hijos se muestren en segundo plano, ya que en primer plano se verán
los controles del formulario MDI padre.

Creando un Formulario MDI Hijo

Para crear un Formulario MDI hijo solo hay que configurar la Propiedad Parent
(disponible solo en tiempo de ejecución) del formulario hijo apuntando al formulario
padre y luego usar el método Show para mostrarlo.
El siguiente código muestra como mostrar un formulario hijo desde un menú:

Protected Sub mnuArchivo_Nuevo_Click(ByVal sender As Object, …)


Dim X As New frmHijo()
X.MDIParent = frmPadre
X.Show()
End Sub

Organizando Formularios MDI Hijos

Si es que desea organizar los formularios MDI hijos se debe usar el método
LayoutMDI del formulario MDI padre junto con una constante de tipo MDILayaout,
que tiene 4 valores: ArrangeIcons, Cascade, TileHorizontal y TileVertical.
A continuación se muestra como ordenar en Cascada los formularios MDI hijos de
un formulario MDI Padre llamado frmPadre:
frmPadre.LayoutMDI(MDILayout.Cascade)

5.11.- Control de Excepciones - Manejo de errores en Visual –Basic

5.11.1.-Tipos de Errores

Los errores o excepciones se pueden clasificar en 3 tipos:


 Errores de Sintaxis: Suceden al escribir código en la aplicación; como por ejemplo una
instrucción mal escrita, omisión de un parámetro obligatorio en una función, etc.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 238


Visual Basic notifica de cualquier error de sintaxis mostrando una marca de subrayado azul
(por defecto) con un comentario indicando la causa del error.

Una ayuda para corregir errores de sintaxis, es usar la sentencia Option Explicit que
fuerce a declarar variables y evitar expresiones inválidas.

 Errores Lógicos: Ocurren una vez usada la aplicación y consiste en resultados


inesperados o no deseados; por ejemplo una función que debe devolver el sueldo neto
está devolviendo un valor de cero o negativo, o una subrutina que debe eliminar un
archivo temporal no lo está borrando.

Para corregir este tipo de errores se hace uso de las herramientas de depuración, como
por ejemplo un seguimiento paso a paso, o inspeccionar el valor de una variable o
expresión.
También podemos disminuir errores o excepciones de tipos de datos no deseados usando
la sentencia Option Strict que evita la conversión forzosa y verifica que el tipo de dato
asignado sea del mismo tipo que la variable o función, o que un parámetro pasado sea del
mismo tipo, etc.
 Errores en Tiempo de Ejecución: Este tipo de errores suceden en plena ejecución de la
aplicación, después de haber sido compilado el código. No son errores de mala escritura
ni de lógica, sino mas bien de alguna excepción del sistema, como por ejemplo tratar de
leer un archivo que no existe o que está abierto, realizar una división entre cero, etc.

Para controlar los errores en tiempo de ejecución disponemos de los Manipuladores o


Controladores de Error, que evitan la caída del programa y permiten que siga
funcionando. A continuación veremos las formas de implementar el control de este tipo
de errores.

5.11.2.-Formas de Controlar Excepciones

Existen dos formas de controlar errores o excepciones en Visual Basic .NET:


5.11.2.1-Control No Estructurado:
Se implementa usando la sentencia On Error GoTo.
Es la forma como se controla errores en las versiones anteriores a Visual Basic .NET y
consiste en el uso de etiquetas, es decir recurrir a la programación etiquetada, cuando
ocurre algún error toma el control el código que se encuentra a continuación de la
etiqueta.
Existen varias sintaxis o formas de usar la sentencia On Error, tal como se define:
1. On Error Resume Next: Indica que si ocurre un error en tiempo de ejecución el flujo
continúe en la siguiente línea después de la que originó el error.

2. On Error GoTo 0: Deshabilita cualquier Controlador de error, previamente


declarado en el procedimiento actual, configurando este a Nothing.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 239


3. On Error GoTo –1: Deshabilita cualquier error o excepción que ocurra en cualquier
línea del procedimiento actual, configurando este a Nothing.

4. On Error GoTo Etiqueta: Si un error en tiempo de ejecución ocurre envía el control


a la instrucción que está debajo de la etiqueta definida. Es la mejor forma no
estructurada de controlar errores, ya que se puede personalizar mensajes. La forma
de implementar esta sentencia en un procedimiento es:

Inicio Procedimiento()
On Error GoTo <Etiqueta>
<Instrucciones>
Exit Sub
<Etiqueta>:
<Instrucciones>
[Resume ¦ Resume Next ¦ Resume Etiqueta]
Fin Procedimiento

Para salir de la etiqueta, generalmente se usa la instrucción Resume, de 3 formas:


 Resume: Vuelve a la instrucción que produjo el error.
 Resume Next: Regresa el flujo a la siguiente instrucción después de la que
produjo el error.
 Resume Etiqueta: Bifurca el control a una etiqueta definida por el usuario.

Al usar la sentencia On Error GoTo si un error en tiempo de ejecución ocurre el control


es tomado por el código de la Etiqueta y la información del error ocurrido es almacenada
en el Objeto Err, tal como el número del error, su descripción y el origen.
5.11.2.2-Control estructurado
Manejo de excepciones estructuradas

Las excepciones en Visual Basic las podemos controlar usando las instrucciones Try / Catch
/ Finally. Estas instrucciones realmente son bloques de instrucciones, al estilo de If / Else.

Cuando queramos controlar una parte del código que puede producir un error lo incluimos
dentro del bloque Try, si se produce un error, éste lo podemos detectar en el bloque Catch,
por último, independientemente de que se produzca o no una excepción, podemos ejecutar
el código que incluyamos en el bloque Finally, para indicar el final del bloque de control de
excepciones lo haremos con End Try.

Inicio Procedimiento()
Try
<Instrucciones Try>
[Exit Try]
[Catch 1 [<Excepción> [As <Tipo Dato>]] [When <Expresión>]]
<Instrucciones Catch 1>
[Exit Try]

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 240


[Catch 2 [<Excepción> [As <Tipo Dato>]] [When <Expresión>]]
<Instrucciones Catch 2>
[Exit Try]
:
:
[Catch n [<Excepción> [As <Tipo Dato>]] [When <Expresión>]]
<Instrucciones Catch n>
[Exit Try]
Finally
<Instrucciones Finally>
End Try
Fin Procedimiento

Cuando creamos una estructura de control de excepciones no estamos obligados a usar los
tres bloques, aunque el primero: Try si es necesario, ya que es el que le indica al compilador
que tenemos intención de controlar los errores que se produzcan. Por tanto podemos crear
un "manejador" de excepciones usando los tres bloques, usando Try y Catch o usando Try y
Finally. Veamos ahora con más detalle cada uno de estos bloques y que es lo que podemos
hacer en cada uno de ellos.

Bloque Try

En este bloque incluiremos el código en el que queremos comprobar los errores.


El código a usar será un código normal, es decir, no tenemos que hacer nada en especial, ya
que en el momento que se produzca el error se usará (si hay) el código del bloque Catch.

Bloque Catch

Si se produce una excepción, ésta la capturamos en un bloque Catch.

En el bloque Catch podemos indicar que tipo de excepción queremos capturar, para ello
usaremos una variable de tipo Exception, la cual pude ser del tipo de error específico que
queremos controlar o de un tipo genérico. Por ejemplo, si sabemos que nuestro código
puede producir un error al trabajar con ficheros, podemos usar un código como este:

Try

' código para trabajar con ficheros, etc.

Catch ex As System.IO.IOException

' el código a ejecutar cuando se produzca ese error

End Try

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 241


Si nuestra intención es capturar todos los errores que se produzcan, es decir, no queremos
hacer un filtro con errores específicos, podemos usar la clase Exception como tipo de
excepción a capturar. La clase Exception es la más genérica de todas las clases para manejo de
excepciones, por tanto capturará todas las excepciones que se produzcan.

Try
' código que queremos controlar

Catch ex As Exception

' el código a ejecutar cuando se produzca cualquier error

End Try

Aunque si no vamos usar la variable indicada en el bloque Catch, pero queremos que no se
detenga la aplicación cuando se produzca un error, podemos hacerlo de esta forma:

Try
' código que queremos controlar

Catch
' el código a ejecutar cuando se produzca cualquier error

End Try

Varias capturas de errores en un mismo bloque Try/Catch

En un mismo Try podemos capturar diferentes tipos de errores, para ello podemos incluir
varios bloques Catch, cada uno de ellos con un tipo de excepción diferente.

Es importante tener en cuenta que cuando se produce un error y usamos varios bloques Catch,
Visual Basic buscará la captura que mejor se adapte al error que se ha producido, pero siempre
lo hará examinando los diferentes bloques Catch que hayamos indicado empezando por el
indicado después del bloque Try, por tanto deberíamos poner las más genéricas al final, de
forma que siempre nos aseguremos de que las capturas de errores más específicas se
intercepten antes que las genéricas.

Evaluación condicional en un bloque Catch

Además de indicar la excepción que queremos controlar, en un bloque Catch podemos añadir
la cláusula When para evaluar una expresión. Si la evaluación de la expresión indicada después
de When devuelve un valor verdadero, se procesará el bloque Catch, en caso de que devuelva
un valor falso, se ignorará esa captura de error.

Esto nos permite poder indicar varios bloques Catch que detecten el mismo error, pero cada

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 242


una de ellas pueden tener diferentes expresiones indicadas con When.

En el siguiente ejemplo, se evalúa el bloque Catch solo cuando el valor de la variable y es


cero, en otro caso se utilizará el que no tiene la cláusula When:

Dim x, y, r As Integer
Try
x = CInt(InputBox(“Introduzca un numero “))
y = CInt(InputBox(“Introduzca otro numero “))
r =x\y
MessageBox.Show("El resultado es: " & r)
Catch ex As Exception When y = 0
MessageBox.Show("No se puede dividir por cero.")
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try

Bloque Finally

En este bloque podemos indicar las instrucciones que queremos que se ejecuten, se produzca
o no una excepción. De esta forma nos aseguramos de que siempre se ejecutará un código, por
ejemplo para liberar recursos, se haya producido un error o no.

Nota:
Hay que tener en cuenta de que incluso si usamos Exit Try para salir del bloque de control de
errores, se ejecutará el código indicado en el bloque Finally.

Captura de errores no controlados

Como es lógico, si no controlamos las excepciones que se puedan producir en nuestras


aplicaciones, estas serán inicialmente controladas por el propio runtime de .NET, en estos
casos la aplicación se detiene y se muestra el error al usuario. Pero esto es algo que no
deberíamos consentir, por tanto siempre deberíamos detectar todos los errores que se
produzcan en nuestras aplicaciones, pero a pesar de que lo intentemos, es muy probable que
no siempre podamos conseguirlo. Por suerte, en Visual Basic tenemos dos formas de
interceptar los errores no controlados:

La primera es iniciando nuestra aplicación dentro de un bloque Try/Catch, de esta forma,


cuando se produzca el error, se capturará en el bloque Catch.

La segunda forma de interceptar los errores no controlados es mediante el evento:


UnhandledException, disponible por medio del objeto My.Application.

Este evento se "dispara" cuando se produce un error que no hemos interceptado, por tanto
podríamos usarlo para prevenir que nuestra aplicación se detenga o bien para guardar en un
fichero .log la causa de dicho error para posteriormente actualizar el código y prevenirlo. Ya

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 243


que cuando se produce el evento UnhandledException, podemos averiguar el error que se ha
producido e incluso evitar que la aplicación finalice. Esa información la obtenemos mediante
propiedades expuestas por el segundo parámetro del evento, en particular la propiedad
Exception nos indicará el error que se ha producido y por medio de la propiedad
ExitApplication podemos indicar si terminamos o no la aplicación.

Nota:
Cuando ejecutamos una aplicación desde el IDE, los errores no controlados siempre se
producen, independientemente de que tengamos o no definida la captura de errores desde el
evento UnhandledException. Ese evento solo se producirá cuando ejecutemos la aplicación
fuera del IDE de Visual Basic

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 244


6.- Programación Orientada a Objeto (POO) en Visual Basic página 170
6.1.- Que es una clase
6.2.- Crear la primea clase
6.3.- Propiedades de solo lectura y escritura
6.4.- Agregar métodos a una clase
6.5.- Agregar evento a una clase
6.6.- Crear una instancia de clase
6.7.- Como utilizar los constructores
6.8.- Como utilizar los destructores
6.9.- Como utilizar los miembros datos compartidos
6.10.- Como utilizar los métodos compartidos
6.11.- Polimorfismo en Visual Basic NET
6.12.- Probar controladores de eventos
6.13.- Herencia de clases en Visual Basic NET

7.- Impresión en Visual Basic página 210


7.1.- La solución: Como imprimir en .NET
7.2.- Las clases para imprimir en .NET
Clase PrintDocument
Clase PrintSetting
Clase PrintDialog
Clase PrintPreviewDialog
Clase PrintPreviewControl
7.4.- Conclusión para imprimir en VB net
7.5.-Hacer Crystal Report con DataSet en Visual Basic.NET
7.6.- Reportes en visual basic.net con Crystal Report
7.7.- Como crear un reporte (ReportViewer)
7.8.- Reportes con datos agrupados (Reporting Service)
7.9.- Dar formato a un reporte (Reporting Service)

8.- Formularios de interfaz múltiple (MDI) página 258


8.1.- Aplicaciones estilo SDI
8.2.- Aplicaciones estilo MD
8.3.- Creación de menú de tipo ventana en formularios MDI
8.4.- Bloqueo de opciones de menús en formularios MDI
8.5.- Recorrer formularios hijos de un MDI
8.6.- Comportamiento no modal
8.7.- Modal de un formulario
8.8.- Controles de cuadro de diálogos de sistema
8.9.- Formularios dependientes
8.10.- Validación de controles.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 245


6.- PROGRAMACIÓN ORIENTADA A OBJETOS (POO) DE
VISUAL BASIC.NET
Introducción:

Todo .NET Framework está basado en clases (u objetos). A diferencia de las versiones
anteriores de Visual Basic, la versión .NET de este lenguaje basa su funcionamiento casi
exclusivamente en las clases contenidas en .NET Framework, además casi sin ningún tipo de
limitación.

La POO es una evolución de la programación por procedimientos llamada también


estructurada. Se basaba en funciones y procedimientos y el código que controlaba el flujo de
las llamadas a estos. En Visual Basic, sobre todo en versiones anteriores se sigue
programando mucho así. A veces por desconocimiento y otras por "miedo" no se da el salto
a la POO, aunque un programador con experiencia en VB puede hacer magníficas
aplicaciones sin utilizar la POO (y sin aprovecharse de sus ventajas), y sobre todo, en un
tiempo relativamente reducido.

6.1.-¿Qué es una clase?

Los programas de Visual Basic se generan con objetos como formularios y controles. Los
objetos también se pueden utilizar para representar cosas reales como personas, equipos
informáticos o incluso algo más abstracto, como una cuenta bancaria.

Una clase es simplemente una representación de un tipo de objeto. Se puede pensar en ella
como un plano que describe el objeto. Así como un plano puede utilizarse para construir
varios edificios, una clase podemos usarla para crear varias copias de un objeto.

Por ejemplo, el control TextBox lo define una clase TextBox, que define su aspecto y sus
funciones. Cada vez que arrastramos un control TextBox a un formulario, realmente está
creando una nueva instancia de la clase TextBox.

Cada control TextBox es una copia exacta, aunque distinta, de la clase que lo define, la clase
TextBox. Puesto que cada objeto es una "instancia" independiente de una clase, la acción de
crear una clase se denomina creación de instancias.

Hasta ahora hemos agregado los controles TextBox a su formulario arrastrándolos desde el
Cuadro de herramientas, pero también puede crear instancias de un objeto TextBox en su
código si utiliza la palabra clave New.

Dim Textbox1 As New TextBox

¿Qué hay dentro de una clase?

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 246


Todos los objetos tienen propiedades que describen sus atributos, métodos que definen sus
acciones y eventos que definen sus respuestas. Igualmente, la clase que define un objeto tiene
sus propias propiedades, métodos y eventos (a veces llamados miembros) que se pasan a
todas las instancias de esa clase.

Por ejemplo, una clase que representa una cuenta bancaria podría tener propiedades como:
NumeroCuenta
BalanceCuenta
CtaBancaria
NumeroCuenta
Métodos como: CambioBalanc
BalanceCuenta
CalculaInteres () e

Eventos : Hacer click


CalculaInteres()
CambioBalance.

Una vez creada la instancia de un objeto de cuenta bancaria, puede tener acceso a sus
propiedades, métodos y eventos de igual manera que si se tratara de un objeto TextBox.

Algunos miembros de una clase son privados; sólo se tiene acceso a ellos mediante código
dentro de la clase. Por ejemplo, una clase de cuenta bancaria puede tener un método para
calcular un saldo. Lo lógico es permitir que un programa lea ese balance pero no que pueda
cambiarlo directamente.

Puede ocultar los miembros de una clase si los declara como Private o exponerlos si los
declara como Public. También puede permitir el acceso a una propiedad y a la vez impedir
que el programa cambie su valor declarándolo como ReadOnly.

El código siguiente muestra cómo podría ser una ejemplo de clase llamada CuentaBanco:

'Declaramos la clase CuentaLimpia


Class CuentaLimpia
'La hacemos privada
Private NumeroCuenta As String
Private BalanceCuenta As Decimal
'Y la ponemos publica para que calcule el balance
Public Sub ActualizaBalance()
End Sub
ReadOnly Property Balance() As Decimal
Get
Return BalanceCuenta
End Get
End Property
End Class

6.2.- Crear la primera clase

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 247


Una de las mejores razones para utilizar clases es que una vez que ha creado una clase para
cierto tipo de objeto, se puede reutilizar esa clase en cualquier proyecto.

Por ejemplo, muchos de los programas que escribimos pueden involucrar personas: Un
programa de administrador de contactos para los contactos comerciales o un programa para
realizar un seguimiento de empleados. Aunque los programas pueden ser considerablemente
diferentes, los atributos que se aplican a cada persona serían los mismos. Todas tienen
nombre, edad, dirección, número de teléfono, etc.

Para empezar a ver mejor crear clases,y usarlas crearemos una clase que represente a una
persona; Podemos guardar esta clase y utilizarla en otros programas que escribamos en el
futuro.

Las clases se pueden crear de tres maneras: como parte del código en un módulo de
formulario en un proyecto de aplicación para Windows, como un módulo de clase separado
agregado a un proyecto de aplicación para Windows o como un proyecto de bibliotecas de
clase independiente.

Crear clases
Al hacer doble clic en un formulario y abrir el Editor de código se ve algo parecido a lo
siguiente:

Public Class Form1


Private Sub Form1_Load...

End Sub
End Class

Podemos observar que el formulario realmente es una clase, marcada por instrucciones
Class y End Class y cualquier código que se haya escrito entre las dos instrucciones es parte
de la clase. Aunque de manera predeterminada un módulo de formulario contiene sólo una
clase única, puede crear módulos adicionales agregando código debajo de la instrucción End
Class, tal como se ilustra a continuación:

Public Class Form1


' El código de nuestro Form va AQUI
End Class
Public Class MiPrimeraClase
' El código de nuestra clase va AQUI
End Class

La desventaja de crear clases de esta manera es que sólo están disponibles dentro del proyecto
donde se crearon. Si deseamos compartir una clase con otros proyectos, puede colocarla en
un módulo de clase.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 248


Módulos de clase
Un módulo de clase es un archivo de código, separado del resto, que contiene una o más
clases. Como es un archivo independiente, se puede reutilizar en otros proyectos.

Los módulos de clase se pueden crear de dos maneras:

 Como un módulo agregado a un proyecto de aplicación para Windows.


 Como un proyecto de bibliotecas de clase independiente

Puede agregar un nuevo módulo de clase a un proyecto existente seleccionando Clase en el


cuadro de diálogo Agregar nuevo elemento, disponible en el menú Proyecto. Para trabajar
en durante el tutorial, crearemos un proyecto de bibliotecas de clases independientes.

Cómo crear un proyecto de de biblioteca de clases:

 En el menú Archivo, seleccionamos Nuevo proyecto.


 En el panel Plantillas, del cuadro de diálogo Nuevo proyecto, hacemos clic en
Biblioteca de clases.

 En el cuadro Nombre, escribimos Persons y hacemos clic en Aceptar.

 Se abrirá un nuevo proyecto de bibliotecas de clase y el Editor de código mostrará el


módulo de clase Class1.vb.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 249


 En el Explorador de soluciones, hacemos clic con el botón secundario del ratón en
Class1.vb y seleccionamos Cambiar nombre y, a continuación, cambiamos el nombre
a "Persons.vb".

Observamos que el nombre en el Editor de código también cambia a Persons.vb.

 En el menú Archivo, elegimos Guardar todo.


 En el cuadro de diálogo Guardar proyecto, hacemos clic en Guardar.

Nota: En lugar de guardar el proyecto en la ubicación predeterminada, podríamos crear un


directorio en el cual podemos almacenar todas las clases para reutilizarlas mas tarde. Se
puede especificar esa carpeta en el campo Location del cuadro de diálogo Guardar proyecto
antes de guardar.

De momento, mantendremos el proyecto abierto, porque lo utilizaremos durante todo el


tutorial, e iremos ampliando la información.

Agregar propiedades a una clase

Todos los objetos tienen atributos y las propiedades representan atributos. Antes, hicimos la
clase "Persons", que representa a una persona; las personas tienen atributos como el nombre
y la edad, por lo que la clase Persons necesita propiedades que representen dichos atributos.

Se pueden agregar propiedades a una clase de dos maneras:

 Como campo.
 Como procedimiento de propiedad.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 250


También podemos determinar cómo funciona una propiedad utilizando los modificadores
Public, ReadOnly o WriteOnly.

Campos y procedimientos de propiedad


Los campos son variables públicas dentro de una clase que se pueden establecer o leer desde
fuera de la clase. Resultan de utilidad para propiedades que no se tienen que validar, por
ejemplo, un valor "Boolean" (True o False).

En el caso de la clase Personas, se puede tener una propiedad Boolean denominada Casado,
que especifica si una persona está soltera o casada, puesto que hay sólo dos valores posibles.
Para agregar un campo a una clase, el código podría ser como el que sigue.

Public Casado As Boolean

La mayoría de las propiedades, sin embargo, son más complejas; en la mayor parte de los
casos utilizaremos procedimientos de propiedad para agregar una propiedad a una clase.

Los procedimientos de propiedad tienen tres partes:

 Una declaración de una variable privada para almacenar el valor de la propiedad.


 Un procedimiento Get que expone el valor.
 Un procedimiento Set que, como indica su nombre, establece el valor en la clase.

Por ejemplo, un procedimiento de propiedad para una propiedad Name, de la clase Personas,
podría ser como el que sigue:

Private ValorNombre As String


Public Property Nombre() As String
Get
Nombre = ValorNombre Recibe el dato en la variable ValorNombre
End Get de
Set(ByVal valor As String) La clase
ValorNombre = valor
End Set
End Property
Devuelve el contenido de la variable
ValorNombre

La primera línea de código declara una variable String privada, ValorNombre que almacenará
el valor de la propiedad. El procedimiento de propiedad en sí comienza con Public Property
y termina con End Property.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 251


El procedimiento Get contiene el código que se ejecutará cuando desee leer su valor; por
ejemplo, si lee la propiedad Personas.Nombre, el código devolverá el valor almacenado en
la variable ValorNombre

El procedimiento Set contiene código que se utiliza para asignar un nuevo valor a la variable
ValorNombre usando un valor pasado como argumento Valor. Por ejemplo, si escribimos el
código

Personas.Nombre = "Carlos"

El valor String Carlos se pasará como argumento Valor; el código del procedimiento Set lo
asignará a la variable ValorNombre para su almacenamiento.

¿Por qué complicarnos tanto, en lugar de utilizar un campo que represente la propiedad
Nombre? En el mundo real, hay ciertas reglas para los nombres: por ejemplo, los nombres
normalmente no contienen números. Puede agregar código al procedimiento Set para
comprobar el argumento Valor y devolver un error si contiene números.

Siguiendo con la Clase Personas, ahora agregaremos un campo y tres propiedades:

1. Abrimos el proyecto Personas que hicimos en la sección anterior. Si no lo guardaste,


primero deberás regresar a la sección anterior, crear la primera clase, y realizar hasta
el final los procedimientos de esa sección.
2. En el Explorador de soluciones, seleccionamos Personas.vb y en el menú Ver
elegimos Código.

3. Agregamos el siguiente código de declaración debajo de la línea Public Class


Personas.

Private ValorPrimerNombre As String

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 252


Private ValorSegundoNombre As String
Private ValorApellido As String
Public Casado As Boolean

4. Agregamos los siguientes procedimientos de propiedad debajo del código de


declaración anterior.

Public Property PrimerNombre() As String


Get
PrimerNombre = ValorPrimerNombre
End Get
Set(ByVal valor As String)
ValorPrimerNombre = Valor
End Set
End Property

Public Property SegundoNombre() As String


Get
SegundoNombre = ValorSegundoNombre
End Get
Set(ByVal valor As String)
ValorSegundoNombre = Valor
End Set
End Property

Public Property Apellido() As String


Get
Apellido = ValorApellido
End Get
Set(ByVal valor As String)
ValorApellido = Valor
End Set
End Property

Quedará así:

5. En el menú Archivo, elegimos Guardar todo para guardar el trabajo.

Propiedades de sólo lectura y escritura


A veces una propiedad se establece una vez y no cambia nunca mas durante la ejecución del
programa. Por ejemplo, una propiedad que representa un número de empleado nunca debe
cambiar, de modo que otro programa si lo pueda leer, pero no se permitirá que ese programa
cambie su valor.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 253


La palabra clave ReadOnly se utiliza para especificar que un valor de propiedad se pueda
leer pero no modificar.

Nota: Si intentamos asignar un valor a una propiedad ReadOnly, aparecerá un error en el


Editor de código.

Para crear una propiedad de sólo lectura, deberemos crear un procedimiento de propiedad
con un procedimiento Get, pero sin procedimiento Set, como se muestra a continuación.

Private IDValue As Integer


ReadOnly Property ID() As Integer
Get
ID = IDValue
End Get
End Property

De igual forma, la palabra clave WriteOnly permite establecer un valor de propiedad pero
no permite que se lea; por ejemplo, no permite que otros programas lean una propiedad de
contraseña. Podemos utilizar ese valor para realizar acciones dentro de la clase, pero deseará
que sigan siendo privadas.

Para crear una propiedad de sólo escritura, se creará una propiedad con un procedimiento Set
pero sin procedimiento Get, como a continuación:

Private passwordValue As String


WriteOnly Property Password() As String
Set(ByVal value As String)
passwordValue = value
End Set
End Property

Los procedimientos de propiedad ReadOnly y WriteOnly también son útiles cuando


deseamos tomar un valor de propiedad y convertirlo en un valor diferente. Por ejemplo,
pensemos en la edad de una persona. A diferencia del nombre, la edad cambia con el tiempo,
si ha asignado la edad a una clase y la lee de nuevo un año después, sería incorrecta.

En la clase Persons, podemos evitarlo agregando dos propiedades: una propiedad "WriteOnly
BirthYear" que representa el año de nacimiento, que nunca cambia, y una propiedad
"ReadOnly Age" que devuelve un valor calculando la diferencia entre el año en curso y el
año de nacimiento.

Siguiendo con la Clase Persons, ahora agregaremos propiedades ReadOnly y WriteOnly a


la clase:

1. Agregamos el siguiente código de declaración debajo de las otras declaraciones en la


parte superior del módulo de clase.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 254


Private birthYearValue As Integer

2. Introducimos los siguientes procedimientos de propiedad debajo del código de


declaración.

WriteOnly Property BirthYear() As Integer


Set(ByVal value As Integer)
birthYearValue = value
End Set
End Property

ReadOnly Property Age() As String


Get
Age = My.Computer.Clock.LocalTime.Year – birthYearValue
End Get
End Property

3. En el menú Archivo, elegimos Guardar todo para guardar el trabajo.

6.4.- Agregar métodos a una clase

Agregaremos métodos a una clase, para que puedan realizar acciones. Vimos que la mayoría
de los objetos tienen acciones que pueden realizar; estas acciones se conocen como
métodos.

La clase Persons que creamos en la sección anterior,tiene muchas acciones que pueden
realizar las personas y, estas acciones se pueden expresar como métodos de clase.

Métodos de una clase

Los métodos de una clase son simplemente procedimientos Sub o Function, declarados en la
clase.

Por ejemplo, una clase Cuenta puede tener un procedimiento Sub denominado Recalcular,
que actualizará el balance o un procedimiento Function denominado CurrentBalance para
devolver el último balance.

El código para declarar esos métodos puede ser similar al siguiente:

Public Sub Recalcular()


'Aqui el codigo para recalcular Cuenta.
End Sub

Ejemplo:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 255


Public Function BalanceCuenta(ByVal AccountNumber As Integer) As Double
'Codigo para volver a Balance
End Function

Si bien la mayoría de los métodos de clase son públicos, también se pueden agregar métodos
que sólo la clase en sí puede utilizar. Por ejemplo, la clase Personas puede tener su propia
función para calcular la edad de una persona. Si declara la función como Private, no se puede
ver o llamar desde fuera de la clase.

El código para una función privada puede ser similar a éste otro:

Private Function CalcuEdad(ByVal year As Integer) As Integer


CalcuAge = My.Computer.Clock.LocalTime.Year - year
End Function

Más tarde podremos cambiar el código que calcula el valor CalcAge y el método seguirá
funcionando bien sin cambiar ningún código que utilice el método. Ocultar el código que
realiza el método, se conoce como la "encapsulación", ya explicada al comienzo.

Ahora, para agregar un método a la clase Persons, hacemos lo siguiente:

Abrimos el proyecto Personas (si no lo tenemos abierto ya de antes) que hicimos en


las secciones anteriores. Si no lo guardaste, o no lo creaste, primero deberás volver a
las secciones anteriores, agregar propiedades a la clase, y completar los
procedimientos.

En el Explorador de soluciones, seleccionamos Personas.vb y, en el menú Ver,


hacemos clic en Código. Agregamos el siguiente código bajo los procedimientos de
propiedad.

Public Function NombreCompleto() As String


If ValorSegundoNombre <> "" Then
NombreCompleto = ValorPrimerNombre & " " &
ValorSegundoNombre & " " & ValorApellido
Else
NombreCompleto = ValorPrimerNombre & " " &
ValorApellido
End If
End Function

Private Function CalcuEdad(ByVal year As Integer) As Integer


CalcuEdad = My.Computer.Clock.LocalTime.Year - year
End Function

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 256


Modificamos el código en el procedimiento de la propiedad Age para utilizar la
función privada:

ReadOnly Property Age() As String


Get
'Age = My.Computer.Clock.LocalTime.Year – birthDateValue
Age = CalcuEdad(birthYearValue)
End Get
End Property

Antes, el código era así:

ReadOnly Property Age() As String


Get
Age = My.Computer.Clock.LocalTime.Year – birthYearValue
End Get
End Property

 En el menú Archivo, hacemos clic en Guardar todo para guardar el trabajo.

6.5.- Agregar eventos a una clase

Un programa puede responder a eventos externos, como por ejemplo, un usuario que hace
clic en un botón. En esta sección, obtendremos información sobre cómo agregar eventos a
una clase.

 Primero, debemos declarar el evento.


 A continuación, debemos provocarlo.

Provocar un evento significa que estamos señalizando la aparición del evento. Para agregar
un evento a una clase, lo declaramos con la instrucción Event. Ésto indica que el objeto
puede provocar el evento que especificamos.

Por ejemplo, quizás deseemos agregar un evento AgeCalculated a la clase Persons que
hicimos. Podemos provocar a continuación el evento en el método CalcAge. Después de
hacer esto, cuando se llama al método, podemos ejecutar algún código adicional en cuanto
se haya calculado la edad de la persona.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 257


Para agregar un evento a la clase Persons

 Abrimos el proyecto Persons.


 En el Explorador de soluciones, seleccione Persons.vb y, en el menú Ver, hacemos
clic en Código.
 Agregamos el siguiente código encima de los procedimientos de propiedad.

Public Event AgeCalculated(ByVal Age As Single)

 En el método CalcAge, reemplazamos el código existente por el siguiente código para


provocar el evento.

Private Function CalcAge(ByVal year As Integer) As Integer


Dim Age = My.Computer.Clock.LocalTime.Year - year
RaiseEvent AgeCalculated(Age)
CalcAge = My.Computer.Clock.LocalTime.Year - year
End Function

 En el menú Archivo, hacemos clic en Guardar todo para guardar el trabajo.

Probar una clase

Creamos una clase llamada "Persons" y le proporcionamos propiedades, métodos y eventos.


Lo que hemos hecho hasta ahora es agregar código, ahora es el momento de utilizar la clase
Persons y asegurarse de que funciona según lo esperado.

6.6.- Crear una instancia de una clase

Los formularios y controles son en realidad clases; cuando arrastramos un control Button a
un formulario, estamos creando realmente una instancia de la clase Button.

También podemos crear instancias de cualquier clase en el código utilizando una declaración
con la palabra clave New. Por ejemplo, para crear una nueva instancia de la clase Button,
agregaremos el código siguiente.

Dim aButton As New Button

Otro ejemplo:

'Declarar e iniciar objeto


Dim objEmpleado As Empleado
objEmpleado = New Empleado()

Para utilizar y probar la clase Persons, debemos crear primero un proyecto de prueba y
agregar una referencia al módulo de clase.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 258


Vemos como crear un proyecto de prueba para la clase Persons

 Abrimos el proyecto Persons que creamos en las secciones anteriores.


 En el menú Archivo, elegimos Agregar y, a continuación, hacemos clic en Nuevo
proyecto.

 En el panel Plantillas, en el cuadro de diálogo Nuevo proyecto, hacemos clic en


Aplicación de Windows Forms.
 En el cuadro Nombre, escribimos PersonsTest y hacemos clic en Aceptar.

 Se agregará un nuevo proyecto de Windows Forms al Explorador de soluciones y


aparecerá un nuevo formulario.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 259


 En el Explorador de soluciones, seleccionamos el proyecto PersonsTest y, en el menú
Proyecto, hacemos clic en Establecer como proyecto de inicio.

 En el Explorador de soluciones, seleccionamos el proyecto PersonsTest y, en el menú


Proyecto, hacemos clic en Agregar referencia.
 Aparecerá el cuadro de diálogo Agregar referencia.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 260


 Hacemos clic en la ficha Proyectos, seleccionamos Personas y hacemos clic en
Aceptar.

 Hacemos doble clic en el formulario para abrir el editor de código y escribimos la


siguiente declaración justo debajo de la línea Public Class Form1.

Dim person1 As New Persons.Persons()

Esto declara una nueva instancia de la clase Persons.

Quizás se preguntén por qué tuvimos que escribir dos veces Persons, pues porque la
primera instancia es el módulo de clase Persons.vb y la segunda instancia es la clase
Persons de ese módulo.

 En el menú Archivo, hacemos clic en Guardar todo.

El siguiente paso es agregar una interfaz de usuario y un código que utilice la clase Persons.

Agregaremos cuadros de texto donde el usuario especificará los valores para cada una de las
propiedades (excepto la propiedad de sólo lectura "Age"), una casilla para el campo
"Married" y botones para probar cada uno de los métodos públicos.

Para probar la clase Personas:

 En el Explorador de soluciones, seleccionamos Form1 y, en el menú Ver, hacemos


clic en Diseñador.
 En el Cuadro de herramientas, arrastramos cuatro controles TextBox, un control
CheckBox y dos controles Button al formulario.
 Seleccionamos el primer control Button y, a continuación, en la ventana Propiedades
establecemos la propiedad Text en Update.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 261


 Seleccionamos el segundo control Button y en la ventana Propiedades establecemos
la propiedad Text en Full Name.
 Hacemos doble clic en el primer botón (Update) para abrir el Editor de código y en
el controlador de eventos Button1_Click, agregamos el siguiente código:

person1.PrimerNombre = Textbox1.Text
person1.SegundoNombre = Textbox2.Text
person1.Apellido = Textbox3.Text
person1.FechaCumpleaños = Textbox4.Text
person1.Casado = CheckBox1.Checked

En el controlador de eventos Button2_Click, agregamos lo siguiente:

MsgBox(person1.NombreCompleto)
MsgBox(CStr(person1.Edad) & " años")

If person1.Casado = True Then


MsgBox(person1.PrimerNombre & " es casado")
Else
MsgBox(person1.Primernombre & " es soltero")
End If

 Presionamos F5 para ejecutar el proyecto y mostrar el formulario:

-En el primer cuadro de texto, escribimos nuestro nombre.


-En el segundo cuadro de texto, escribimos nuestro segundo nombre.
-En el tercer cuadro de texto, escribimos nuestro apellido.
-En el cuarto cuadro de texto, escribimos el año de nuestro nacimiento con
cuatro dígitos (por ejemplo, 1983).
-Activamos la casilla de si estamos casados/as.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 262


 Hacemos clic en el botón "Update" para establecer las propiedades de la clase y clic
en el botón "Full Name".

Se muestran tres cuadros de mensaje. Estos cuadros de mensaje muestran su nombre


completo, edad y estado civil.

En el menú Archivo, hacemos clic en Guardar todo.

Segundo ejemplo completo de programa de uso de clase en Visual Basic


NET
Ejemplo Calcular el salario de un empleado, información a sacar por pantalla Nombre del
empleado y Salario semanal, datos conocidos: nombre, número de horas trabajadas y pago
por hora del empleado
El salario se calcula de la manera siguiente:
Si el número de horas trabajadas es mayor que 40, el excedente de 40 se paga al doble de la
cuota por hora, en caso de no ser mayor que 40 se paga a la cuota por hora normal.
Realicemos la solución de acuerdo al modelo-vista-controlador
Solución:
1.- programamos la clase empleado en el módulo de clase

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 263


Public Class Empleado
'Declaraciones de Datos
Private NombreEmpleado As String
Private HorasTrabajadas As Integer
Private PagoHora As Double
Private Salario As Double

Public ReadOnly Property obtenerNombre() As String


' bloque Get obtener para devolver el valor de la propiedad
Get
Return NombreEmpleado
End Get
End Property
Public WriteOnly Property establecerNombre() As String
' bloque Set (Establecer) para asignar valor a la propiedad
Set(ByVal Value As String)
NombreEmpleado = Value
End Set
End Property
Public ReadOnly Property obtenerHoras() As Integer
' bloque Get para devolver el valor de la propiedad
Get
Return HorasTrabajadas
End Get
End Property
Public WriteOnly Property EstablecerHoras() As Integer
' bloque Set para establecer valor a la propiedad
Set(ByVal hora As Integer)
HorasTrabajadas = hora
End Set
End Property
Public WriteOnly Property EstablecerPago() As Double
' bloque Get para devolver el valor de la propiedad
Set(ByVal value As Double)
PagoHora = value
End Set
End Property
End class
2.- Programamos el form como clase principal. la clase Ejecuta
Rem Clase Ejecuta Empleado (Esta se encuentra en el Form)
Public Class Form1
Public NEmple As String
Dim HT As Double

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 264


Dim PagoH As Double

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles Button1.Click
'Declarar e iniciar objeto
Dim objEmpleado As Empleado
objEmpleado = New Empleado()
'Trasladar datos a las variables
NEmple = TextBox1.Text
HT = Val(TextBox2.Text)
PagoH = Val(TextBox3.Text)
'Metodos establecer
objEmpleado.establecerNombre = NEmple
objEmpleado.EstablecerPago = PagoH
objEmpleado.EstablecerHoras = HT
'Metodo Calcular
objEmpleado.CalcularSalario()
'Metodos obtener datos
Label4.Text = "Empleado " & UCase(objEmpleado.obtenerNombre)
Label5.Text = "Pago por hora " & objEmpleado.ObtenerPagoHora
Label6.Text = "Salario " & objEmpleado.ObtenerSalario
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
End
End Sub
End Class

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 265


6.7.-Cómo utilizar los constructores
Introducción

En Visual Basic .NET, la inicialización de nuevos objetos se controla utilizando


constructores. Para crear un constructor para una clase, se crea un procedimiento denominado
Sub New en cualquier lugar de la definición de la clase.

Características de Sub New

El constructor Sub New tiene las siguientes características:


El código del bloque Sub New siempre se ejecutará antes de cualquier otro código de una
clase.
El constructor Sub New solo se ejecutará una vez, cuando se cree un objeto.

Ejemplo de Sub New

El siguiente ejemplo muestra cómo utilizar el constructor Sub New:

Public Sub New( )


' Perform simple inicialización
intValue = 1
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 266


La siguiente línea de código crea un objeto desde una clase denominada BankAccount, ya
definida en la aplicación.

Dim myAccount As New BankAccount( )

Podemos sobrecargar New y crear tantos constructores de clases como sean necesarios. Esto
resulta útil si deseamos inicializar nuestro objeto cuando lo creemos.

Sobrecarga de constructores
Podemos sobrecargar constructores del mismo modo que se sobrecarga cualquier otro
método de una clase. No obstante, no podemos utilizar la palabra clave Overloads cuando
sobrecargamos constructores. El siguiente ejemplo muestra cómo sobrecargar New y crear
múltiples constructores de clase:

Class CuentaBanco
Private balance as Double
Sub New( )
' Inicializar balance
balance = 0.0
End Sub
Sub New(ByVal cantidad As Double)
balance = cantidad
End Sub
End Class

Uno de los constructores del ejemplo anterior toma un parámetro. Si estamos creando un
objeto desde tal clase, podemos incluir sus parámetros en la declaración. El siguiente ejemplo
muestra cómo invocar el método New que toma un parámetro.

Dim miCuenta As New CuentaBanco(120.00)

Para escribir nuestros propios constructores de clase, crearemos un método con el nombre
New( ), como vemos en el Código. En dicho ejemplo, al instanciarse un objeto de
la clase Empleado, se asignará a una de sus propiedades la fecha actual.
Interfase grafica cliente
Public class form1…..
Private Sub Botton_Click …
Dim loEmp As Empleado
loEmp = New Empleado()
MsgBox("El objeto se ha creado el día " & loEmp.FechaCrea)
End Sub
End class
Public Class Empleado
Private mdtFechaCrea As Date
Public Property FechaCrea() As Date

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 267


Get
Return mdtFechaCrea
End Get
Set(ByVal Value As Date)
mdtFechaCrea = Value
End Set
End Property
' método constructor
Public Sub New()
' asignamos un valor inicial a una variable de propiedad
Me.FechaCrea = Now
End Sub
End Class

Al igual que ocurre en un método normal, New( ) admite parámetros; esto nos sirve
para asignar valores de inicio al objeto en el momento de su instanciación. La
denominación para este tipo de métodos es constructor parametrizado. El Código nos
muestra una variación del fuente anterior, utilizando un constructor de este tipo.

Interfase grafica cliente


Public class form1…..
Private Sub Botton_Click …
Dim loEmp As Empleado
loEmp = New Empleado("5/7/2002")
MsgBox("El objeto se ha creado el día "& loEmp.FechaCrea)
' este es otro modo de instanciar un objeto con un constructor
parametrizado
Dim loEmp2 As New Empleado("08/4/2002")
End Sub
End Class

Public Class Empleado


Private mdtFechaCrea
Public Property FechaCrea() As Date
Get
Return mdtFechaCrea
End Get
Set(ByVal Value As Date)
mdtFechaCrea = Value
End Set
End Property

' método constructor con parámetro


Public Sub New(ByVal ldtFecha As Date)
' asignamos el valor del parámetro a una variable de propiedad
Me.FechaCrea = ldtFecha
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 268


End Class

Combinando las características de métodos constructores junto a las de sobrecarga,


podemos crear un conjunto de constructores sobrecargados para la clase.
Public Class Empleado
Public psNombre
Public psApellidos
Public psCiudad
Private mdtFechaCre

' en este constructor sin parámetros, asignamos la fecha actual


Public Sub New()
mdtFechaCrea = Now()
End Sub
' en este constructor, asignamos valores a todos los campos de la clase
Public Sub New(ByVal lsNombre As String, ByVal lsApellidos As String, ByVal
lsCiudad As String)
psNombre = lsNombre
psApellidos = lsApellidos
psCiudad = lsCiudad
End Sub
End Class

6.8.-Cómo utilizar los destructores


Introducción

En Visual Basic .NET, podemos controlar qué ocurre durante la destrucción de objetos
utilizando procedimientos denominados destructores.

Finalize y Dispose

El sistema invoca al destructor Finalize antes de liberar el objeto. Puede utilizarse para
limpiar recursos abiertos, como conexiones a bases de datos, o para liberar otros recursos.
Sin embargo, existe una demora entre el momento en que un objeto pierde su alcance y el
momento en que se invoca al destructor Finalize.

La ejecución de Sub Finalize provoca una ligera pérdida en el rendimiento, por ello
únicamente debería definirse un método Sub Finalize cuando sea necesario liberar objetos
explícitamente.

Visual Basic .NET permite un segundo tipo de destructor, denominado Dispose, que puede
ser invocado explícitamente en cualquier momento para liberar recursos de forma inmediata.
Dispose no se incluye en el ámbito de este curso. Si desea más información sobre Dispose,

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 269


puede consultar “Duración de los objetos: cómo se crean y destruyen” en la documentación
de Visual Studio .NET.

Nota

Ejemplo de Sub Finalize

El siguiente ejemplo muestra cómo utilizar el destructor Finalize:

Protected Overrides Sub Finalize( )


' Puedo cerrar conecciones u otros recursos
conn.Close
End Sub

Protected es un modificador de acceso que establece el nivel de accesibilidad.

6.9.-Cómo utilizar miembros de datos compartidos


Introducción

En Visual Basic .NET, los miembros de datos compartidos pueden utilizarse para permitir
que múltiples instancias de una clase hagan referencia a una única variable a nivel de clase.
Sintaxis: Utilizaremos la siguiente sintaxis para declarar miembros de datos compartidos:

NiveldeAcceso Shared MiembrodeDatos As TipodeDatos

Niveles de acceso

Los miembros de datos compartidos están directamente enlazados a la clase, y podemos


declararlos como públicos o privados. Si declaramos los miembros de datos como públicos,
estarán accesibles para cualquier código que pueda acceder a la clase. Si declaramos los
miembros de datos como privados, proporcionaremos propiedades compartidas públicas para
acceder a la propiedad compartida privada.

El siguiente ejemplo muestra cómo crear una clase de cuenta de ahorro (SavingsAccount) que
utilice un miembro de datos compartido público para mantener los tipos de interés para una
cuenta de ahorro:

Class GuardaCuenta
Public Shared TasaInteres As Double
Public Function CalculaInteres( ) As Double
...
End Function
End Class

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 270


El valor del miembro de datos TasaInteres de la clase GuardaCuenta puede establecerse
globalmente con independencia del número de instancias de la clase que estén en uso. El
valor se utiliza para calcular el interés del saldo actual.

Invocar miembros de datos compartidos desde un cliente

Después de crear una clase que utilice miembros de datos compartidos públicos, podemos
invocar los miembros de datos de esa clase desde una aplicación cliente. El siguiente código
muestra cómo invocar la clase GuardaCuenta y sus miembros de datos desde una aplicación
cliente:

Sub Test( )
GuardaCuenta.TasaInteres = 0.03
Dim miCuenta As New GuardaCuenta( )
Dim tuCuenta As New GuardaCuenta( )
MessageBox.Show(miCuenta.CalculaInteres( ))
MessageBox.Show(tuCuenta.CalculaInteres( ))
End Sub

En el examen de este código, se observa lo siguiente:

TasaInteres puede establecerse antes y después de la creación de cualquier instancia de la


clase GuardaCuenta. Cualquier modificación a TasaInterest se aplicará a todas las
instancias de la clase GuardaCuenta

Propiedades compartidas

También pueden crearse propiedades compartidas en las clases. El siguiente ejemplo muestra
cómo declarar una propiedad compartida denominada Tasa en la clase GuardaCuenta:

Class GuardaCuenta
Private Shared TasaInteres As Double
Shared Property Tasa( ) As Double
Get
Return TasaInteres
End Get
Set(ByVal Value As Double)
TasaInteres = Value
End Set
End Property
End Class

Invocar propiedades compartidas desde un cliente

Una vez declarada la propiedad compartida Tasa, puede utilizarse en una aplicación cliente
en lugar de acceder directamente al miembro de datos compartido TasaInteres. Podemos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 271


invocar una propiedad compartida cualificándola con el nombre de clase o con el nombre de
variable de una instancia específica de la clase.

El siguiente código muestra cómo invocar una propiedad compartida cualificándola con el
nombre de la clase:

GuardaCuenta.Tasa = 0.03

6.10.-Cómo utilizar los métodos compartidos


Introducción

Podemos utilizar los miembros de procedimiento compartidos para diseñar funciones que
pueden ser invocadas sin crear una instancia de la clase. Los procedimientos compartidos son
métodos de una clase que no están asociados a una instancia específica de una clase. Los
miembros de procedimiento compartidos únicamente pueden acceder a datos marcados con
la palabra clave Shared. Por ejemplo, un método compartido no puede hacer referencia a un
miembro de la instancia de una clase.

Ejemplo del uso de un miembro de procedimiento compartido

El siguiente ejemplo muestra cómo una función utilizada habitualmente, como


ObtenerNombrePC, puede crearse como un miembro de procedimiento compartido de
forma que una aplicación cliente puede utilizarla fácilmente. El cliente únicamente necesita
hacer referencia al método prefijado por el nombre de la clase, ya que no se requiere ninguna
instancia de la clase.

' Codigo de la clase TestClass


Public Shared Function ObtenerNombrePC ( ) As String
...
End Function

' Codigo Cliente


MessageBox.Show(TestClass. ObtenerNombrePC ( ))

Observaremos también que, en el código anterior, Show es un método compartido de la clase


MessageBox.

6.11.-¿Qué es el polimorfismo?

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 272


Introducción
La mayoría de sistemas de programación orientada a objetos proporcionan polimorfismo
mediante herencia. El polimorfismo basado en herencia implica la definición de métodos en
una clase base y sobrecargarlos con nuevas implementaciones en clases derivadas.

Definición

Polimorfismo hace referencia a la capacidad de definir múltiples clases con diferentes


funcionalidades pero con métodos o propiedades de nombres idénticos que pueden utilizarse
de forma intercambiable por el código cliente en tiempo de ejecución. El nombre del método
reside en la clase base. Las implementaciones de métodos residen en las clases derivadas.
Para gestionar esto, únicamente puede declararse en la clase base el nombre del método (no
el código que proporciona la funcionalidad del método).

La función getBonificacion sobrecargada en el ejemplo de l grafica

Otro Ejemplo de polimorfismo

Supongamos que definimos una clase denominada ImpuestoGeneral que proporciona


funcionalidad básica para calcular el impuesto sobre las ventas de un estado. Las clases
derivadas de ImpuestoGeneral, como ImpuestoRegion o ImpuestoCiudad, podrían
implementar métodos como CalculaImpuesto.

Polimorfismo hace referencia al hecho de que la implementación del método


CalculaImpuesto podría ser distinta en cada una de las clases derivadas. Por ejemplo, el tipo

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 273


impositivo de una ciudad (ImpuestoCiudad) podría ser distinto del tipo impositivo de una
region (ImpuestoRegion). Las clases que hereden de ImpuestoGeneral tendrán un método
CalculaImpuesto, pero el modo como se calcule realmente el impuesto podría variar en cada
una de las clases derivadas.

Sobrecarga de métodos o polimorfismo, en una misma clase


La sobrecarga de métodos, es una técnica que consiste en crear varios métodos con
idéntico nombre dentro de la misma clase, distinguiéndose entre sí por su lista de
parámetros.

Métodos sobrecargados

Para crear un método sobrecargado, agregamos dos o más procedimientos Sub o Function a
la clase, cada uno con el mismo nombre. En las declaraciones de procedimiento, el conjunto
de argumentos para cada procedimiento debe ser distinto o se producirá un error.

El siguiente ejemplo muestra un método con dos sobrecargas, una que acepta una String y la
otra que acepta un Integer como argumentos.

Public Sub TestFunction(ByVal input As String)


MsgBox(input)
End Sub
Public Sub TestFunction(ByVal input As Integer)
MsgBox(CStr(input))
End Sub

Si se debe llamar a este método desde el código y pesarle una cadena, se ejecutaría la primera
sobrecarga y un cuadro de mensaje mostraría la cadena; si se le pasó un número, se ejecutaría
la segunda sobrecarga y el número se convertiría en una cadena y aparecería en el cuadro de
mensaje.

Podemos crear tantas sobrecargas como sean necesarias y cada una de ellas puede contener
un número diferente de argumentos.

Analicemos el siguiente ejemplo:


Interfase grafica cliente
Public class form1…..
Private Sub Botton_Click …
Dim loEmpleado As New Empleado()
Dim ldbResultadoIncent As Double
loEmpleado.Salario = 1020.82

'llamada al primer método sobrecargado


loEmpleado.Sueldo()

'llamada al segundo método sobrecargado

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 274


MsgBox("El sueldo se transferirá el día " & loEmpleado.Sueldo(29))

'llamada al tercer método sobrecargado


ldbResultadoIncent = loEmpleado.Sueldo(50.75, "Extras")
MsgBox(“El incentivo a pagar será " & ldbResultadoIncent)
End Sub
End Class

Ahora veamos el codigo de la clase empleado con el uso de la sobrecarga

Public Class Empleado


Private mdbSalario As Double
Public Property Salario() As Double
Get
Return mdbSalario
End Get
Set(ByVal Value As Double)
mdbSalario = Value
End Set
End Property
' Métodos sobrecargados

Public Overloads Sub Sueldo()


' aquí mostramos en consola el importe del sueldo formateado
MsgBox("El sueldo es " & Format(Me.Salario, "#,#.##"))
End Sub

Public Overloads Function Sueldo(ByVal liDia As Integer) As String


' Aquí mostramos la fecha del mes actual en la que se
' realizará la transferencia del sueldo al banco del empleado
Dim ldtFechaActual As Date
Dim lsFechaCobro As String
ldtFechaActual = Now()
lsFechaCobro = CStr(liDia) & "/" & _
CStr(Month(ldtFechaActual)) & "/" & _
CStr(Year(ldtFechaActual))
Return lsFechaCobro
End Function

Public Overloads Function Sueldo(ByVal ldbImporteIncentivo As Double,ByVal


lsTipoIncentivo As String) As Double
' aquí calculamos la cantidad de incentivo que se añadirá al
' sueldo del empleado,en función del tipo de incentivo
Dim ldbIncentivo As Double
' según el tipo de incentivo, se descuenta un importe de la cantidad del
‘ incentivo
Select Case lsTipoIncentivo

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 275


Case "Viajes"
ldbIncentivo = ldbImporteIncentivo - 30
Case "Extras"
ldbIncentivo = ldbImporteIncentivo - 15
End Select
Return ldbIncentivo
End Function
End Class

6.13.- Herencia en Visual Basic NET


La Herencia especifica una relación “es un tipo de”

Múltiples clases comparten los mismos atributos y operaciones, permitiendo una eficaz
reutilización del código

Persona Clase base

Cliente Empleado Clase Derivada

Introducción

En Visual Basic .NET, la herencia puede utilizarse para derivar una clase de una clase
existente. La clase derivada puede heredar todas las propiedades, métodos, miembros de
datos, eventos y controladores de eventos de la clase base, facilitando la reutilización de la
clase base por toda la aplicación.

Definición

Herencia es el concepto de reutilizar atributos y operaciones comunes de una clase base en


una clase derivada.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 276


Cómo heredar de una clase
Una clase derivada hereda de una clase base
Pueden heredarse propiedades, métodos, miembros de datos, eventos y controladores de
eventos (dependiendo del ámbito)
La palabra clave Inherits

La palabra clave Inherits se utiliza para definir una clase derivada que heredará de una
clase base existente.

Ejemplo: El siguiente ejemplo muestra cómo utilizar la palabra clave Inherits:

Public Class VefirificaCuenta


Inherits CuentaBanco
Private Sub ProcesarCheque( )
' Agregar codigo para procesar uncheque en su cuenta
End Sub
End Class

Observacion Podemos utilizar la palabra clave MyBase para invocar métodos en una clase
base cuando invalidan métodos en una clase derivada. También podemos utilizar la palabra
clave MyBase para invocar el constructor y el destructor de la clase base en nuestra clase
derivada.

Observemos el siguiente ejemplo:

'Crear clase derivada en dos líneas


Public Class Administrativo
Inherits Empleado

' Crear clase derivada en la misma línea


Public Class Administrativo : Inherits Empleado
La palabra clave NotInheritable

La palabra clave NotInheritable se utiliza para definir una clase que no puede utilizarse
como clase base para herencia. Si otra clase intenta heredar de esta clase, se generará un error
de compilación.

Ejemplo: El siguiente ejemplo muestra cómo utilizar la palabra clave NotInheritable:

Public NotInheritable Class TestClass


...
End Class
Public Class DerivedClass
' La linea de abajo genera un error del compilador
Inherits TestClass
...

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 277


End Class

La palabra clave MustInherit

La palabra clave MustInherit se utiliza para definir clases que no están pensados para ser
utilizados directamente como objetos instanciados. La clase resultante debe ser heredada
como una clase base para utilizarla en el objeto de una clase derivada instanciada.

Ejemplo: El siguiente ejemplo muestra cómo utilizar la palabra clave MustInherit:

Public MustInherit Class ClaseBase


...
End Class
...
Si el código cliente intenta crear una instancia de este tipo de clase, se generará un error de
compilación, como se muestra en el siguiente ejemplo:
' Codigo Cliente
' La linea de abajo genera un error del compilador
Dim x As New BaseClass( )

La palabra clave Protected

Utilizamos el acceso Protected para limitar el ámbito de una propiedad, método, miembro
de datos, evento o controlador de eventos a la clase que los define y cualquier clase derivada
basada en esa clase base.

Ejemplo

El siguiente ejemplo muestra cómo utilizar la palabra clave Protected:

Public Class BaseClass


' Accesible en todo
Public counter As Integer
' Accessible solo en esta lcase o en clases derivadas
Protected nombre As String
...
End Class

Generar una clase a partir de una clase existente: Herencia de clases

Muchos objetos de la vida real tienen atributos y comportamientos en común, por ejemplo,
todos los coches tienen ruedas y motores, y pueden avanzar y detenerse. Sin embargo,
algunos automóviles tienen atributos que no son comunes, por ejemplo, un descapotable tiene
una parte superior que se puede subir/bajar electrónica o manualmente.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 278


Si se creó un objeto para representar un automóvil, se pueden incluir propiedades y métodos
para todos los atributos y comportamientos comunes, pero no se podrían agregar atributos
como la cubierta de un descapotable, puesto que dicho atributo no es generalizable a todos
los automóviles.

Mediante el uso de la herencia, se puede crear una clase "descapotable" que deriva de la clase
"automóvil". Ésta hereda todos los atributos de la clase automóvil y puede agregar los
atributos y comportamientos que son únicos de un auto descapotable.

Heredar a partir de una clase existente

La instrucción Inherits se utiliza para declarar una nueva clase, denominada clase derivada,
basada en una clase existente conocida como clase base. Las clases derivadas heredan todas
las propiedades, los métodos, los eventos, los campos y las constantes definidos en la
clase base.

El siguiente código muestra la declaración de una clase derivada.

Class DerivedClass
Inherits BaseClass

End Class

Se pueden crear instancias de la nueva clase DerivedClass, se puede tener acceso a sus
propiedades y métodos como BaseClass y se pueden agregar nuevas propiedades y métodos
que son específicos de la nueva clase. Para ver un ejemplo, nos fijaremos en la clase Persons
que tenemos creada.

Supongamos que deseamos tener una clase que represente jugadores de béisbol: los jugadores
del béisbol tienen todos los atributos definidos en la clase Personas, pero también tienen
atributos únicos, como su número y posición. En lugar de agregar esas propiedades a la clase
Personas, se creará una nueva clase derivada que se hereda de Personas, a la que se agregaran
las nuevas propiedades.

Pasos para crear una clase derivada de la clase Personas:

 Abrimos el proyecto Personas que llevamos todo el tutorial usando.


 En el Explorador de soluciones, seleccionamos el nodo del proyecto Personas.
 En el menú Proyecto, elegimos Agregar clase.
 En el cuadro de diálogo Agregar nuevo elemento, escribimos Jugadores en el cuadro
Nombre, a continuación, hacemos clic en Agregar.
 Se agregará un nuevo módulo de clase al proyectollamado Jugadores.
 En el Editor de código, agregamos lo siguiente justo debajo de la línea Public Class
Jugadores.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 279


Inherits Personas

 Agregamos también el siguiente código para definir las dos nuevas propiedades.
Private Vnumero As Integer
Private Vposicion As String
Public Property Numero() As Integer
Get
Numero = Vnumero
End Get
Set(ByVal value As Integer)
Vnumero = value
End Set
End Property
Public Property Posicion() As String
Get
Posicion = Vposicion
End Get
Set(ByVal value As String)
Vposicion = value
End Set
End Property

 En el menú Archivo, hacemos clic en Guardar todo.

Probar la clase Jugadores

Hemos creado una clase Jugadores, derivada de la clase Personas. Ahora haremos una nueva
aplicación para probar la clase Jugadores.

Para crear un proyecto de prueba para la clase:

1. En el menú Archivo, elegimos Agregar y, a continuación, hacemos clic en Nuevo


proyecto.
2. En el cuadro de diálogo Agregar nuevo proyecto, en el panel Plantillas,
seleccionamos una Aplicación de Windows Forms.
3. En el cuadro Nombre, escribimos PruebaJugadores y hacemos clic en Aceptar.
4. Se agregará un nuevo proyecto de Windows Forms al Explorador de soluciones y
aparecerá un nuevo formulario.
5. En el Explorador de soluciones, seleccionamos el proyecto PruebaJugadores y, en el
menú Proyecto, hacemos clic en Establecer como proyecto de inicio.
6. En el Explorador de soluciones, seleccionamos el proyecto PruebaJugadores y, en el
menú Proyecto, haga clic en Agregar referencia.
7. Se abrirá el cuadro de diálogo Agregar referencia.
8. Hacemos clic en la ficha Proyectos, elegimos Personas y hacemos clic en Aceptar.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 280


9. Hacemos doble clic en el formulario para abrir el Editor de código y escribimos la
siguiente declaración justo debajo de la línea Public Class Form1.

Dim player1 As New Personas.Jugadores


Dim player2 As New Personas.Jugadores

Esto declara dos nuevas instancias de la clase Players.

10. En el menú Archivo, hacemos clic en Guardar todo.

Para probar la clase derivada:

1. En el Explorador de soluciones, seleccionamos Form1 en el proyecto


PruebaJugadores y, a continuación, en el menú Ver, hacemos clic en Código.
2. En el Editor de código, agregamos el siguiente código al procedimiento de evento
Form1_Load.

Player1.FirstName = "Marvin"
Player1.LastName = "Garcia"
Player1.Number = 13
Playere1.Position = "Shortstop"

player2 .FirstName = "Jose"


player2.LastName = "Black"
player2..Number = 51
player2 .Position = "Catcher"

3. En el Explorador de soluciones, seleccionamos Form1 en el proyecto


PruebaJugadores y, a continuación, en el menú Ver, hacemos clic en Diseñador.
4. En el Cuadro de herramientas, arrastramos dos controles Button al formulario.

5. Seleccionamos el primer control Button y en la ventana Propiedades establecemos su


propiedad Text : Al bate.
6. Seleccionamos el segundo control Button y en la ventana Propiedades establecemos
su propiedad Text : En el banco
7. Hacemos doble clic en el primer botón (Al bate) para abrir el Editor de código y
escribimos el siguiente código en el controlador de eventos Button1_Click.

MsgBox(player1.Posicion & " " & player1.FullName & ", #" &
CStr(player1.Numero) & " esta ahora al bate.")

Observamos que estamos utilizando el método FullName que se heredó de la clase


base Persons.

8. En el controlador de eventos Button2_Click, agregamos el siguiente código.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 281


MsgBox(player2.Position & " " & player2.FullName & ", #" &
CStr(player2.Numero) & " esta en el banco.")

9. Presionamos F5 para ejecutar el programa. Hacemos clic en cada botón para ver los
resultados.

9.1 Clic al Boton1(Al bate):

9.2. Clic al Boton2 (en el banco):

10. En el menú Archivo, elegimos Guardar todo.

Hemos visto, qué son y cómo crear clases, agregarle propiedades, métodos y eventos, las
hemos heredado, etc. la mejor forma de aprender y de que las cosas se entiendan, es
haciéndolo uno mismo, es decir escribir programas utilizando todas las herramientas
posibles…

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 282


7.- Impresión en Visual Basic .NET
Introducción
Lo primero que debemos tener en cuenta es que todo lo que queramos hacer en .NET
debemos hacerlo usando las clases que este entorno nos ofrece y el tema de imprimir no es
una excepción.

En .NET ha cambiado un poco la forma de hacer todo lo que hacíamos en VB6, ya no existen
"objetos" que nos permitan imprimir ni colecciones que nos permitan saber las impresoras
disponibles, bueno, un poco sí, pero como veremos de una forma más ordenada y algo
diferente. En los siguientes puntos veremos que puede ser más soportable e incluso más fácil
si aprendemos a manejar las clases de .NET que nos permiten imprimir y configurar las
opciones de impresión.

7.1.-La solución: Cómo imprimir en .NET

Básicamente para imprimir en .NET solamente necesitamos una clase: PrintDocument la


cual está definida en el espacio de nombres System.Drawing.Printing. Con esta clase
tenemos todo lo necesario para imprimir (en la impresora predeterminada) cualquier tipo de
documento.

Simplemente necesitamos llamar al método Print y asunto arreglado. Seguramente el lector


se preguntará que si esto es así, ¿dónde está el problema? Problema, lo que se dice problema,
realmente no hay ninguno, lo que ocurre es que esta clase, particularmente el método Print,
se utiliza sin tener que indicar qué es lo que queremos imprimir, y aquí es donde podría estar
ese problema. El método Print de la clase PrintDocument lo que realmente hace es
"despertar a la bestia", es decir, dar las instrucciones pertinentes al motor de .NET para que
se inicie el proceso de impresión, dicho proceso se lleva a cabo básicamente utilizando el
evento PrintPage de la clase PrintDocument, en este evento es donde tendremos que hacer
todo lo necesario para que se imprima lo que queramos imprimir.

Por tanto, para poder controlar lo que se va a imprimir, debemos escribir todo nuestro código
en ese evento, el cual se produce para cada página que deba imprimirse en el evento
PrintPage, por tanto podemos decir que en .NET es más fácil imprimir y sobre todo controlar
cómo y dónde se imprime cada cosa, ya que, si lo simplificamos al máximo, todo se hace en
un solo sitio: el evento PrintPage de la clase PrintDocument.

Ejemplo de impresión

En el listado podemos ver un ejemplo de la forma más simple de imprimir en .NET, en este
ejemplo mostramos la cadena "Hola, Mundo" en la parte superior de la página usando una
fuente Arial de 24 puntos en negrita.

Private Sub btnImprimirSimple_Click(ByVal sender As Object, _


ByVal e As EventArgs)Handles btnImprimirSimple.Click

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 283


' ejemplo simple para imprimir en .NET
' Usamos una clase del tipo PrintDocument
Dim printDoc As New PrintDocument
' asignamos el método de evento para cada página a imprimir
AddHandler printDoc.PrintPage, AddressOf print_PrintPage
' indicamos que queremos imprimir
printDoc.Print()

End Sub

Private Sub print_PrintPage(ByVal sender As Object, _


ByVal e As PrintPageEventArgs)
'Este evento se producirá cada vez que se imprima una nueva página
' imprimir HOLA MUNDO en Arial tamaño 24 y negrita
' imprimimos la cadena en el margen izquierdo
Dim xPos As Single = e.MarginBounds.Left
' La fuente a usar
Dim prFont As New Font("Arial", 24, FontStyle.Bold)
' la posición superior
Dim yPos As Single = prFont.GetHeight(e.Graphics)

' imprimimos la cadena


e.Graphics.DrawString("Hola, Mundo", prFont, Brushes.Black, xPos, yPos)
' indicamos que ya no hay nada más que imprimir
' (el valor predeterminado de esta propiedad es False)
e.HasMorePages = False
End Sub

Ejemplo simple de impresión


Como podemos comprobar el proceso es bien simple:

 Primero tenemos el código usado para dar la orden de imprimir, (este código puede
estar en el evento Click de un botón), en el que creamos un nuevo objeto del tipo
PrintDocument al que asignamos el procedimiento de evento a usar cuando se vaya a
imprimir cada página, cosa que ocurrirá después de llamar al método Print de esta
clase.
 En el evento PrintPage le indicamos a .NET que es lo que queremos imprimir, en
nuestro caso sólo la cadena "Hola, Mundo", para imprimir dicho texto utilizamos el
método DrawString del objeto Graphics, (una propiedad del segundo parámetro
pasado al evento).

Esta simpleza es en parte porque tampoco hacemos demasiadas cosas en el código del evento
PrintPage, aunque aquí mostramos algunas de las cosas necesarias, como por ejemplo indicar
el tipo de fuente a usar para la impresión, la cual se puede cambiar en cada una de las líneas
a imprimir (e incluso en distintas partes de esa línea), ya que cada línea se "dibuja" por medio

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 284


del método DrawString del objeto Graphics obtenido del segundo parámetro pasado a este
método.

Como vemos en DrawString debemos indicarle que es lo que queremos imprimir, con qué
tipo de fuente y en qué posición. Por último indicaremos si quedan más páginas a imprimir,
esto lo haremos asignado un valor verdadero o falso a la propiedad HasMorePages del objeto
recibido como segundo parámetro del evento, si el valor asignado es True estaremos
indicando que queremos seguir imprimiendo, por el contrario, asignando un valor False
terminaremos la impresión, cosa que también ocurrirá si no le asignamos expresamente nada
a esa propiedad.

7.2.-Configurar la impresión

Pero para ser claros esta no será la forma "habitual" de usar este evento, ya que en la mayoría
de los casos imprimiremos más de una página y seguramente querremos asignar otros valores
a la impresora, como los márgenes, el número de copias, el tamaño del papel, la orientación
de la impresión (vertical o apaisada) e incluso, lo más importante, qué impresora usar.

Todos estos valores los podremos indicar usando un objeto del tipo PrinterSettings, el cual,
entre otras cosas, nos permite saber cuáles son las impresoras que tenemos disponibles en el
equipo actual. Por tanto, lo habitual será que usemos un objeto de esta clase en conjunto con
el de la clase principal para imprimir: PrintDocument.

Seleccionar la impresora a usar

Otra de las tareas que seguramente nos veremos en la necesidad de ofrecer a los usuarios de
nuestras aplicaciones es que puedan seleccionar de una manera fácil qué impresora usar y
darles la posibilidad de que ajusten sus preferencias de impresión.

Todo esto lo podríamos hacer manualmente creando un formulario que utilice un objeto del
tipo PrinterSettings y que le ofrezca a los usuarios las opciones que creamos conveniente,
pero para que todo sea, digamos, más homogéneo y no tengamos que reinventar la rueda,
podemos hacer que toda esta configuración y selección de la impresora a usar la ofrezcamos
mediante los mismos cuadros de diálogo que utiliza el resto de aplicaciones, los cuales se
basan en los cuadros de diálogos comunes del sistema operativo, si esta es nuestra elección,
nos resultará fácil, ya que podemos usar la clase PrintDialog.

Con un objeto de esta clase, tal como hemos comentado, podemos mostrar el mismo cuadro
de diálogo que utilizan el resto de aplicaciones de Windows, con la ventaja añadida de que
podemos configurar las opciones que se mostrarán, de forma que lo configuremos para que
se adapte, en la medida de lo posible, a las preferencias de nuestra aplicación.

En breve veremos cuáles son las opciones que podemos usar para ajustar este cuadro de
diálogo a nuestras preferencias o a la de nuestra aplicación.

7.3.-Las clases para imprimir en .NET

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 285


Como hemos comentado en los párrafos anteriores, existen varias clases que nos permitirán
tanto imprimir como configurar la impresión. Todo esto es posible gracias a las clases que
.NET Framework pone a nuestra disposición para poder realizar esta tarea.

Echando mano del comodín que los que nos dedicamos a escribir artículos o libros, tenemos
que decir que en este artículo no disponemos del espacio suficiente para enumerar en detalle
todas las clases, delegados y enumeraciones que tanto el espacio de nombres
System.Drawing.Printing como System.Windows.Forms pone a nuestra disposición para
realizar tareas relacionadas con la impresión, por tanto haremos una pequeña criba para
mostrar solamente los tipos que desde nuestro punto de vista pueden resultarnos más útiles,
particularmente porque serán los que utilicemos en la mayoría de los casos.

La clase PrintDocument
Esta es la clase elemental o principal si queremos imprimir en .NET, como hemos comentado
anteriormente, de los miembros que esta clase ofrece principalmente usaremos tres:

 El método Print es el que iniciará el proceso de impresión, haciendo que se produzcan


los eventos necesarios para controlar lo que queremos imprimir.
 El evento PrintPage, el cual se producirá cada vez que tengamos que imprimir una
página. Dentro de este evento es donde haremos todo lo que tengamos que hacer para
imprimir cada una de las páginas, desde aquí podemos controlar si quedan más
páginas por imprimir, etc.
 La propiedad PrinterSettings a la que podemos asignarle un objeto del mismo nombre
en el que indicamos la impresora a usar y otros valores como el rango de página, el
número de copias, el tamaño del papel, la orientación, etc.

Del resto de miembros de esta clase podemos destacar la propiedad DocumentName a la que
podemos asignar el nombre del documento que estamos imprimiendo y que será el que se
muestre en el estado de la impresión. También tenemos el evento QueryPageSettings el cual
se produce justo antes del evento PrintPage y que nos permite asignar valores "particulares"
a cada una de las páginas a imprimir antes de que se produzca el evento PrintPage.

La clase PrinterSettings

Tal y como hemos estado indicando en los párrafos anteriores, esta clase nos permite
especificar características de impresión como la impresora a usar, el número de copias a
imprimir, el rango de páginas, etc. Realmente no necesitamos indicar nada, al menos de
forma explícita para usar un objeto de esta clase, ya que al crear una nueva instancia los
valores predeterminados serán los que tengamos asignado en la impresora, valga la
redundancia, predeterminada de nuestro sistema. Pero si queremos modificar esos valores,
tendremos que asignarlos a las propiedades de esta clase, entre las que podemos destacar las
siguientes:

 Copies indica el número de copias a imprimir.


 FromPage indica la página a partir de la que queremos imprimir.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 286


 MaximunPage indica el número máximo de copias que se pueden indicar.
 MinimunPage es el número mínimo de copias que podemos indicar.
 ToPage indica la página hasta la que queremos imprimir.

Tanto MaximunPage como MinimunPage se utilizarán para indicar los valores máximo y
mínimo de las páginas disponibles y se usarán con una clase del tipo PrintDialog.

Del resto de propiedades también podemos destacar las colecciones:

 InstalledPrinters es una propiedad compartida y por tanto podemos usarla sin


necesidad de crear una instancia de la clase PrinterSettings, esta colección devuelve
un array de tipo String con el nombre de cada una de las impresoras instaladas en el
sistema.
 PaperSizes es una colección con elementos del tipo PaperSize que nos permite saber
los tamaños de papel que la impresora soporta. Cada elemento del tipo PaperSize nos
proporciona información sobre el tamaño (ancho y alto), el nombre y la "clase" de
papel, que no es ni más que una enumeración del tipo PaperKind.
 PrinterResolutions es una colección con elementos del tipo PrinterResolution, de
forma que podamos averiguar las resoluciones (y calidades) permitidas por la
impresora. Cada uno de estos elementos nos indicará tanto la resolución horizontal
como la vertical, además de la calidad de impresión, especificada con uno de los
valores de la enumeración PrinterResolutionKind, cuyos valores pueden ser: Custom,
Draft, High, Low y Medium.

De los métodos, posiblemente el que más nos puede interesar es:

 CreateMeasurementGraphics el cual nos permite conseguir un objeto del tipo


Graphics con el cual podemos averiguar ciertas características de la impresora sin
necesidad de tener que imprimir, ya que el objeto devuelto por este método es igual
al que se incluye en la clase PrintPageEventArgs, usada como segundo parámetro en
los eventos producidos por la clase PrintDocument.

Como regla general deberíamos tener una variable del tipo PrinterSettings para usarla como
almacenamiento de las preferencias de impresión de nuestros usuarios, ya que esta clase se
utiliza tanto con PrintDocument como con PrintDialog.

La clase PrintDialog
Esta clase nos servirá para que nuestros usuarios seleccionen la impresora a usar así como
para que indiquen ciertas características relacionadas con la impresión, como la calidad del
papel, el número de copias, etc., con la ventaja de que todo esto lo haremos usando el mismo
cuadro de diálogo común incluido en Windows y que es el que la práctica totalidad de
aplicaciones de este sistema operativo utilizarán, tal como podemos comprobar en la figura
1.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 287


Figura 1. El cuadro de diálogo para seleccionar la impresora

En la figura 1 podemos comprobar que hay ciertos elementos que puede que no nos interese
mostrar o dejar habilitados, por ejemplo, si nuestra aplicación no permite imprimir el código
seleccionado no tiene mucho significado ofrecerle la opción "Selección", (la figura está
capturada de un Windows XP en inglés, por eso se muestran las opciones en inglés), lo mismo
ocurre con el botón de ayuda o con las cajas de texto que permiten indicar el rango de páginas
a imprimir. Todas estas características las podemos habilitar o deshabilitar mediante algunas
de las propiedades de la clase PrintDialog, tales como: AllowPrintToFile, AllowSelection,
AllowSomePages, PrintToFile, ShowHelp y ShowNetwork.

La ayuda del cuadro de diálogo de imprimir


Como curiosidad, decir que la propiedad ShowHelp nos permite indicar si se debe mostrar o
no el botón de ayuda, (no la interrogación de la barra de títulos que siempre estará funcional),
pero entre las propiedades de esta clase no tenemos ninguna a la que indicarle que ayuda se
debe mostrar si pulsamos en ese botón, en lugar de eso, de lo que disponemos es de un evento:
HelpRequest el cual se producirá cuando el usuario pulse en dicho botón, por tanto si
queremos mostrar algún tipo de ayuda, tendremos que usar ese evento para mostrar la
información que creamos conveniente para nuestro cuadro de diálogo.

Al igual que en el resto de cuadros de diálogos de .NET, tenemos el método ShowDialog que
será el que nos permita mostrar el cuadro de diálogo y saber si el usuario ha pulsado en el
botón OK (Aceptar) o Cancelar, para que de esta forma sepamos si debemos seguir con el
proceso de impresión o no.

La propiedad PrinterSettings será la que nos permita saber lo que el usuario ha seleccionado,
además de ser la que usemos para asignar los valores predeterminados o bien los que
tengamos almacenado de ocasiones anteriores; tal como indicamos anteriormente, lo habitual
será que tengamos una variable del tipo de esta propiedad con las preferencias del usuario,

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 288


por tanto antes de llamar al método ShowDialog deberíamos asignar a esta propiedad la
variable que tengamos con las preferencias del usuario y si no se ha cancelado, debemos
asignar nuevamente el resultado de dichas preferencias, tal como mostramos en el listado 2.

Private Function seleccionarImpresora() As Boolean


Dim prtDialog As New PrintDialog
If prtSettings Is Nothing Then
prtSettings = New PrinterSettings
End If
With prtDialog
.AllowPrintToFile = False
.AllowSelection = False
.AllowSomePages = False
.PrintToFile = False
.ShowHelp = False
.ShowNetwork = True
.PrinterSettings = prtSettings
If .ShowDialog() = DialogResult.OK Then
prtSettings = .PrinterSettings
Else
Return False
End If
End With
Return True
End Function

La clase PrintPreviewDialog
Esta clase nos permitirá mostrar una ventana con la vista preliminar del documento que
queremos imprimir, de forma que los usuarios de nuestra aplicación pueden ver lo que se
imprimirá. Debido a que esta clase al estar derivada de Form tiene todas las propiedades,
métodos y eventos de cualquier formulario además de los relacionados con la
previsualización del documento a imprimir, veamos solamente los dos miembros que nos
interesarán más:

 El método ShowDialog será el que se encargue de mostrar el formulario con la vista


preliminar.
 A la propiedad Document le asignaremos un objeto del tipo PrintDocument que será
el que utilicemos para saber qué es lo que queremos imprimir.

NOTA:
Por regla general deberíamos asignar a la propiedad Document de la clase
PrintPreviewDialog el mismo objeto PrintDocument usado para imprimir, ya que la
clase PrintPreviewDialog se encargará de que se produzcan los mismos eventos que
si hubiésemos llamado al método Print del objeto PrintDocument asignado, de forma
que lo que se muestre mediante este diálogo sea lo mismo que se imprima, que es al
fin y al cabo lo que queremos conseguir.
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 289
Tal como hemos resaltado en la nota, tanto el método Print de la clase PrintDocument como
la clase PrintPreviewDialog utilizan los mismos eventos del objeto PrintDocument, por tanto
podríamos usar un método genérico que sea el encargado de mostrar una vista preliminar de
lo que queremos imprimir o de mandarlo a la impresora, de esta forma podemos usar de
forma común las opciones ofrecidas al usuario, como por ejemplo permitir la selección de la
impresora antes de imprimir, etc.

En el listado podemos ver cómo podría ser ese método genérico para elegir entre imprimir o
previsualizar lo que deseamos imprimir.

Private Sub imprimir(ByVal esPreview As Boolean)


' imprimir o mostrar el PrintPreview
If prtSettings Is Nothing Then
prtSettings = New PrinterSettings
End If

If chkSelAntes.Checked Then
If seleccionarImpresora() = False Then Return
End If
If prtDoc Is Nothing Then
prtDoc = New System.Drawing.Printing.PrintDocument
AddHandler prtDoc.PrintPage, AddressOf prt_PrintPage
End If

' la línea actual


lineaActual = 0
' la configuración a usar en la impresión
prtDoc.PrinterSettings = prtSettings

If esPreview Then
Dim prtPrev As New PrintPreviewDialog
prtPrev.Document = prtDoc
prtPrev.Text = "Previsualizar documento"
prtPrev.ShowDialog()
Else
prtDoc.Print()
End If
End Sub

Tal como podemos ver en la figura, el formulario (o cuadro de diálogo) de previsualización


nos permite seleccionar el número de página a mostrar, si queremos ver una o más páginas a
un mismo tiempo, el porcentaje de ampliación e incluso imprimir lo que estamos viendo,
todos estas características ya están incluidas en ese formulario.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 290


El formulario de previsualización

La clase PrintPreviewControl

Si nuestra intención es crear nuestro propio formulario de previsualización, también podemos


hacerlo si usamos el control PrintPreviewControl que es el que la clase PrintPreviewDialog
utiliza, si bien todos los botones y opciones tendremos que crearlos nosotros, para ello
podemos usar los miembros específicos de este control, tales como:

 AutoZoom lo usaremos para que al cambiar el tamaño del control se cambie también
la página mostrada.
 Columns indica el número de páginas a mostrar cuando se elija la orientación
horizontal (apaisada).
 Document es donde asignaremos el objeto PrintDocument a imprimir.
 Rows indica el número de páginas a mostrar cuando elijamos la orientación vertical.
 Zoom para indicar la ampliación con la que queremos mostrar los documentos.
 StartPageChanged en un evento que se producirá cada vez que cambiemos la página
de inicio (este evento nos servirá para crear un equivalente al NumericDropDown
usado en la clase PrintPreviewDialog).

Si también quisiéramos implementar un botón para imprimir, tendremos que manejar


nosotros mismos la impresión, pero realmente resultaría fácil, ya que lo único que tendríamos
que hacer es llamar al método Print del objeto PrintDocument asignado a la propiedad
Document.

Como siempre la última palabra la tendremos nosotros y dependiendo de lo que queramos


hacer usaremos una clase u otra.

7.4.- Conclusión para imprimir en VB net

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 291


Tal como hemos podido comprobar, imprimir en .NET no es tan complicado como en un
principio pudiera parecer, además de que tenemos valores añadidos que nos permiten un
mayor control sobre la impresión y, especialmente, sobre las opciones que podemos ofrecer
a los usuarios de nuestras aplicaciones, ya que como hemos visto, hacer algo como la
presentación preliminar, que en otros lenguajes nos obligaría a escribir bastante código, es
tan sencillo como crear un nuevo objeto en la memoria y asignar un par de propiedades.

Por supuesto, lo que no es totalmente sencillo ni automático es la presentación o impresión


de los datos que necesitamos mostrar, al menos si queremos darle un toque, digamos,
profesional a nuestra impresión, ya que seremos nosotros los que debamos "afinar" en la
forma de mostrar esos resultados; pero de todas formas eso es algo que siempre nos tocará
hacer, utilicemos el entorno de programación que utilicemos, la ventaja de usar lo que .NET
nos ofrece es que tenemos ciertas posibilidades de hacerlo de una forma más o menos fácil y
que de alguna forma nos facilita bastante la tarea, aunque para la mayoría de situaciones será
más que suficiente e incluso podemos automatizar, principalmente porque podemos
aprovechar las posibilidades que nos da la programación orientada a objetos de crear nuestras
propias clases e implementar métodos de impresión que se adapten a los datos que tengamos
que mostrar, ya que una de las claves de la POO es la abstracción y que mejor forma de
abstracción que crear un método que se encargue de manejar los datos que la propia clase
mantiene y que "sepa" cómo mostrar esos datos e incluso qué formato deben aplicarse a la
hora de presentar esos datos por la impresora. Posiblemente tengamos que quemar unas
cuantas neuronas más a la hora de "concebir" esa clase, pero a la larga ese esfuerzo habrá
valido la pena ya que puede suponernos una forma de "olvidarnos" de esos pequeños detalles
de ajustar cada una de las líneas que vamos a imprimir.

De seguro que el lector puede pensar que tampoco es necesario ese "esfuerzo" extra para
imprimir una línea, y seguramente tenga razón, pero precisamente si cuando diseñamos
nuestras clases para manejar datos tenemos en cuenta estos detalles, seguramente nos
resultará más fácil realizar cambios en ocasiones futuras. Por ejemplo, si tenemos una clase
en la que hay datos de cadena y de tipo numérico y queremos mostrar esos datos, la forma de
tratar cada uno de esos datos será diferente, ya que con toda seguridad los datos numéricos
querremos ajustarlos a la derecha y los de cadena a la izquierda, además de que si debemos
recortar la información que tenemos que mostrar, con total seguridad preferiremos "truncar"
los datos de cadena antes que los numéricos.

En este tipo de situaciones si dejamos que el código de la clase sea el que decida estos
truncamientos, (realmente el código de la clase no va a decidir nada, ya que tendremos que
ser nosotros los que hagamos esa decisión), siempre será preferible que tener que hacerlo en
el propio evento de impresión, sobre todo si ese mismo evento es el que usaremos para
imprimir datos de diferentes tipos, que pueden proceder de diferentes clases, pero si las clases
usadas para contener los datos están "preparadas" para imprimir el contenido de cada línea,
entonces resultará tan sencillo como llamar a un método de cada una de esas clases... En el
listado podemos ver cómo quedaría el evento PrintPage si hiciéramos algo de lo que
acabamos de comentar.

' El evento usado mientras se imprime el documento


Private Sub prt_PrintPage(ByVal sender As Object, ByVal e As PrintPageEventArgs)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 292


' Este evento se produce cada vez que se va a imprimir una página
Dim lineHeight As Single
Dim yPos As Single = e.MarginBounds.Top
Dim leftMargin As Single = e.MarginBounds.Left
Dim printFont As System.Drawing.Font
' Asignar el tipo de letra
printFont = prtFont
lineHeight = printFont.GetHeight(e.Graphics)
Dim fontTitulo As New Font("Arial", 20, FontStyle.Bold)
e.Graphics.DrawString("Listado de " & Título, fontTitulo, _
Brushes.Black, leftMargin, yPos)
yPos += fontTitulo.GetHeight(e.Graphics)
' imprimir la cabecera de la página
yPos = Datos(0).CabeceraImpresión(e, printFont, yPos)
' imprimir cada una de las líneas de esta página
Do
yPos += lineHeight
e.Graphics.DrawString(Datos(lineaActual).LineaImpresión, _
printFont, Brushes.Black, leftMargin, yPos)
lineaActual += 1
Loop Until yPos >= e.MarginBounds.Bottom _
OrElse lineaActual >= Datos.Count
If lineaActual < Datos.Count Then
e.HasMorePages = True
Else
e.HasMorePages = False
End If
End Sub

7.5.-Como crear un reporte (Reportviewer)

Mostraremos en esta oportunidad cómo crear un reporte en visual basic .net utilizando
reporting services y el control reportView.

Lo primero que necesitamos es crear una conexión a una base de datos, y lo haremos de
la siguiente manera: Desde el explorador de servidores (si no lo ves podes activarlo desde
el menú Ver/Explorador de Servidores [Crtl+Alt+S]), creamos una nueva conexión.
Seleccionamos SQL Server como se ve ne la imagen:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 293


Luego debemos proporcionar los datos de conexión a nuestro servidor (Puedes presionar
el botón [Probar Conexión] para asegurarte de que los datos son correctos). Puedes usar
cualquier base de datos para el ejemplo:

Cuando finalices la conexión se verá como en la siguiente imagen:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 294


Ahora debemos agregar un nuevo origen de datos a nuestra aplicación:

Los origenes de datos pueden ser desde una base de datos, un servicio web o un objeto.
Para este ejemplo usamos una base de datos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 295


Seleccionamos la conexión que creamos anteriormente.

Damos nombre a la conexión y seleccionamos siguiente:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 296


Puede que nuestra base de datos tenga varias tables, seleccionamos la tabla que
utilizaremos:

Al finalizar se verá como en la imagen siguiente, si no lo ves, selecciona el menú


Datos/Mostrar Origenes de Datos [Shift+Alt+D]:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 297


Ya tenemos nuestro Origen de DAtos listo para ser utilizado. Ahora agregaremos un
informe (report) a nuestro proyecto:

Seleccionamos Informe:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 298


Se mostrará el diseñador de informes. Agrega una tabla al informe.

Se verá más o menos así:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 299


Podemos agregar o quitar columnas haciendo clic con el botón derecho del mouse sobre
alguna columna.

Desde el panel Origenes de Datos arrastramos los campos sobre fila del medio de la tabla.
Como se ve en la imagen:

Luego en el Formulario Windows agregamos un control ReportView.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 300


Desde la etiqueta inteligente del control seleccionamos nuestro reporte (report1.rdlc):

Luego, desde la misma etiqueta, seleccionamos Acoplar en el contenedor principal:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 301


Notaremos que al seleccionar el informe, como el informe ya tenía una tabla con datos de
un origen de datos, se han creado en forma automática los componentes Dataset,
TableAdapter y Binding Sources correspondientes.

Bueno, solo nos queda ejecutar la aplicación. El resultado debería parecerse al de la


siguiente imagen:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 302


Los reportes ofrecen varias funcionalidades mas que no he comentado por falta de
tiempo. Lo haré en futuros post. Espero que les sirva este ejemplo. hasta la próxima
entrega.

7.5.1.- Reportes con datos agrupados (Reporting Service)

Mostraremos como podemos hace un reporte con datos agrupados en visual basic .net.

Nuestro reporte tiene el siguiente aspecto:

Seleccionamos la fila de los datos (la del medio) y haciendo clic con el botón derecho del
mouse, desplegamos el menú contextual y seleccionamos Insertar Grupo.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 303


Esto nos abrirá una ventana de propiedades de agrupación y ordenación. Para crear un
grupo (en mi caso voy a agrupar los productos por marca) seleccionamos el campo que
contiene el dato desde la lista desplegable de Expresión para la sección Agrupar por:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 304


Al presionar aceptar en el cuadro anterior, vemos que nos agregó una fila antes y otro
despues de la fila de los datos. Estas filas son el encabezado y pie de grupo.

En mi caso me pareció útil combinar las celdas del encabezado de grupo por si alguna
marca tiene un nombre muy largo.

Sobre la fila de los encabezados de grupo arrastro y suelto el campo marca desde el panel
de origenes de datos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 305


Para el pie de grupo, en la columna precio arrastro y suelto desde elk panel origenes de
datos el campo precio. La diferencia es que al soltarlo sobre una celda de grupo le coloca
automaticamente la función SUM por lo que el resultado será la suma de los precios de los
artículos de ese grupo. Para que el total del grupo tenga el mismo formato que los precios
individuales, puedo agregar la funcion FORMAT igual que en la celda de arriba.

Bueno, aquí esta el reporte… la verdad que quedó bastante lindo…

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 306


Espero que les guste y por sobre todo que lo puedan usar en sus proyectos

7.5.2.- Dar formato a un reporte (Reporting service)

En base al ejemplo anterior (8.7.Cómo crear un reporte), quiero mostrarles como


podemos “formatear” ese reporte para conseguir un presentación mucho más profesional
utilizando reporting services desde visual basic .net.

Abrimos el reporte sobre el cual trabajaremos, se verá más o menos como este:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 307


Lo primero que tenemos que hacer es verificar si tenemos visibles las dos barras de
herramientas que necesitaremos para darle formato al informe, ellas son: “Bordes del
informe” y “Formato del informe”. Si no están visibles las podemos habilitar desde
Ver/Barras de Herramientas.

Para cambiar el color de alguna celda de la tabla, seleccionamos la celda y desplegamos la


ventana Color de fondo desde la barra de herramientas Formato del informe. En ella
tenemos atodos los colores web que usamos normalmente en los formularios windows.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 308


También podemos aplicarle formato de borde a cualquier celda de la tabla desde la barra
de herramientas Bordes del informe.

Podemos aplicar el tipo de letra a varias celdas al mismo tiempo seleccionando varias
celdas y aplicando el formato.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 309


Es muy útil la opción de combinar celdas. Seleccionamos más de una celda de una misma
fila y desde el menu contextual (el que se abre al presionar clic con el botón derecho del
mouse) seleccionamos la opción Combinar celdas.

Para cualquier texto que querramos que aparesca en el informe utilizamos un Cuadro de
Texto.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 310


Por defecto, al colocar en la tabla un campo numérico, este se alinea hacia la derecha. Si
lo deseamos esto se puede cambiar utilizando la barra de formato. En nuestro caso
utilizaremos la función Format para dar formato numérico al precio. Botónderecho sobre
la celda Precio y seleccionamos Expresión…

El cuadro Editar expresión es muy completo, te recomiendo que le des una mirada,
Usamos la función Format con el formato “Fixed” que nos monstrará los números con dos
decimales.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 311


Así se debería ver el informe terminado:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 312


7.6.-Trabajar Crystal Report con DataSet en Visual Basic.NET
La mayoría de las veces que trabajamos con Visual Basic .Net y Crystal Report, solemos
conectarnos a SQL Server u Oracle como fuente de datos, debido a que tienen integración
con el IDE de Visual Studio, para facilitar la creación de los mismos.

Cuando hablamos de motores como PostgreSQL, MySQL, Firebird, Teradata y otros, no


tenemos la integración del IDE con el servidor de base de datos, esto hace que no podamos
crear tan sencillamente los reportes como los hacemos como con los otros motores, pero no
lo hace imposible, sólo se debe seguir unos pasos distintos, que también sirve para los 2
primeros motores mencionados anteriormente.

Lo siguiente sirve en muchos casos para proyectos pequeños de la universidad, a pesar de


que utlizaré Visual Studio 2008 esto sirve muy bien para Visual Studio 2005 también, asi que
comencemos:

1.- Procederé a crear un proyecto en Visual Basic 2008, con el Framework 2.0, y le pondré
de nombre EjemploReporteCrystal, obviamente si ya tienen el proyecto creado no deben
de hacerlo.

2.- Después lo que hacemos es insertar un DataSet de nuestra base de datos, si no sabes
como hacerlo da clic aquí.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 313


3.- Luego de eso agregamos un nuevo elemento, para esto damos clic derecho en nuestro
proyecto –> Agregar –> Nuevo

Elemento.

4.- Tendremos un formulario como el siguiente en donde escogeremos la opción de la


izquierda, seleccionamos Reporting –> Seleccionamos ahora Crystal Report –> Le ponemos
un nombre –> y damos clic en Adjuntar.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 314


5.- Ahora lo que veremos será un wizard o ayudante que nos permitirá crear un reporte de
manera sencilla, deberán entonces de ver una imagen como la siguiente y darle clic en ok.
Dejen las opciones tal como las tengo en mi imagen.

6.- Lo siguiente es escoger de donde sacaremos los datos que mostraremos, para esto en la
siguiente pantalla que se les mostrará que deberá ser como la imagen que coloco abajo,
ustedes deberán escoger Datos del Proyecto –> ADO.NET DataSets –>
EjemploReporteCrystal.BD_EjemploProcedimientosDataSet (Este es mi dataset que puse
enante, entonces aquí colocan el de ustedes) –> y escogen las tablas que utilizarán en su
reporte, en mi caso escogí 2, ya que utilizaré datos de las 2 tablas –> Presionamos el boton
“>” para cada tabla que queramos utilizar en el reporte y una vez hecho esto damos en
siguiente.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 315


7.- En la siguiente pantalla veremos como están relacionadas las tablas, no hay
practicamente nada que explicar asi que damos clic en siguiente.

8.- Ahora en esta pantalla siguiente si hay que poner asunto, porque es aquí en donde
diremos que campos de que tablas y en qué lugar los queremos en nuestro reporte,
entonces vemos como tengo mis 2 tablas y escojo los datos que necesito de las 2, sin
preocuparme de como estén relacionadas ni nada por el estilo, como ven en esta parte lo
que hago es darle sentido a la forma de presentar mis datos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 316


9.- Luego de esto vendrán ciertas opciones como la que utilizaré a continuación que es de
agrupar los datos en un cierto orden, y la forma que escogi de agruparlos es por géneros
iguales, esto lo hago especificando en la parte de agrupamiento qué campo es el que quiero
agrupar.

10.- Lo que sigue son más opciones como les dije, pero en este momento yo ya le di en
finalizar, ya que no necesito hacerle más cosas a mi reporte, por ahora. Luego de dar clic en
finalizar tendré una imagen como la que está abajo, la parte que tengo tachada es una parte
que no quiero mostrar en ejecución por tanto para ocultarlas les damos clic derecho en la
parte gris y al desplegarse un menú de opciones seleccionamos ocultar.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 317


11.- Bien ahora regresamos y abrimos nuestro form, y buscamos nuestro origen de datos,
si no lo vemos por ahi, damos clic en el menú de Visual Studio en la opción de Datos –>
Seleccionamos ver Origenes de Datos y listo, tendrán que poder ver su dataset con las tablas
al lado como en la imagen. Pero bueno lo que debemos hacer con esto es arrastrar esas 2
tablas a mi formulario, y esto para qué es? pues es para colocar esos controles que ven
abajo junto con el dataset que están encerrados en el rectángulo verde, son controles que
ya vienen cargados con datos necesarios y que no tendremos que ponerlos nosotros, por
ejemplo ruta de la base de datos o metodos de conexión y desconexión, etc.

12.- Después de poner esas tablas las sacamos junto con la barra que se pone en la parte
superior, y deberá quedarnos tener algo como lo que sigue.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 318


13.- Luego de lo que hicimos vamos a la caja de herramientas y buscamos un control
llamado CrystalReportViewer, lo arrastramos y colocamos en el formulario, este control
será el que nos permita vizualizar nuestro reporte hecho anteriormente.

14.- Entonces una vez hecho esto damos doble clic en el borde del form para entrar al
metodo load del mismo y poner el codigo que sigue a continuación. Aclarando un poco
sobre ese código, lo que hacen las 2 primeras líneas es filtrar los datos de las tablas
indistintamente si están relacionadas, las otras 3 líneas sirven para cargar nuestro reporte
en el reportviewer que pusimos en el form, para esto cree un objeto llamado rpt del
reporte(), que fue mi reporte que creamos hace rato, y en su propiedad SetDataSource le
envie el dataset del proyecto que obviamente ya tiene los datos filtrado gracias a las 2 líneas
primeras, por último mande a cargar este reporte al control del form con su propiedad
ReportSource.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 319


15.- Luego de esto si lo ejecutan deberán ver algo como esto.

16.- Ahora abramos el DataSet para crear algo extra, a continuación lo que haremos es crear
un método que nos filtree solo los datos de las personas de género masculino. Para esto
demos doble clic sobre el dataset o clic derecho y Open.

17.- Damos clic derecho sobre la tabla en la que crearemos el filtro –> Adjuntar –> Query.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 320


18.- Lo que haremos a las siguientes 2 pantallas es simplemente darles clic en siguiente.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 321


19.- Luego tendremos esto y lo que haremos es agregar otra tabla para relacionarla con la
actual, para esto damos clic derecho en la parte blanca al lado de la tabla y en las opciones
que se despliegan seleccionamos Adjuntar Tabla.

20.- Ya que nuestra Base de Datos solo posee 2 tablas solo podremos escoger 1, que es la
tabla TGenero que es la que no tenemos puesta, la seleccionamos y damos clic en Adjuntar
y luego en Cerrar.

21.- Como vemos a continuación ya nos aparece la tabla que agregamos relacionada con la
primera que teniamos, esto es debido a que ya desde que las creamos hicimos esta relación;
lo que sigue el como se ve en la imagen poner en la parte del medio o directamente en el
query que necesitamos de la tabla TGenero el campo nombre_genero y que este nos servirá
como filtro, por eso colocamos en la parte de filtro la palabra =@nombre_genero además
debemos de sacar este campo de área Select, ya que si lo dejamos ahí no nos mostrará
datos en nuestro reporte, o por lo menos eso es lo que me ha sucedido en la práctica,
porque si lo ejecutamos en ese instante con el botón Execue Query si funciona
normalmente pero con el Crystal Report encontre esa falla.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 322


22.- Ya al haberle dado clic en OK debe de presentarnos la siguiente imagen en la
cual veremos ya hecha nuestra sentencia query de consulta, damos clic en siguiente para
continuar.

23.- Ahora le pondremos un nombre tanto en la parte donde dice Fill a DataTable como
en Return a DataTable, damos clic en siguiente.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 323


24.- Lo que viene es que ejecutará lo que hicimos en el DataSet y guardará los cambios,
solo le damos clic en Finalizar.

25.- Ahora en el código modificaremos la línea que hacia el filtro en la tabla TPersona, en
mi caso la puse como comentario, y coloqué la que cree recién, pueden ver que después
del DataSet le pongo una coma y le envio un parámetro, esto es debido a que en mi query
le puse el @nombre_genero, entonces por cada parámetro así que pongamos en el query
que hicimos debemos enviarlo aquí es esa línea después del DataSet en el orden que nos lo
pide la instrucción; en ese código yo puse la opción masculino directamente, si nosotros la
colocaramos o escogieramos desde un textbox o un combobox este sería el que pondríamos
ahí con su propiedad text.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 324


26.- Ya lo que queda es ejecutar la aplicación y podremos ver que solo nos filtrará los
datos de las personas de género masculino.

7.7.- Ejemplo de Reportes en visual basic.net con Crystal


Reports
En esta ocasión veremos cómo generar reportes en visual basic.net usando Crystal Reports.
Antes que nada, realizar la conexión a la base de datos .

Una vez que tenemos lo anterior, procederemos a crear la parte de reportes.

Primeramente, agregaremos 2 botones más al formulario que creamos en la conexión a la


base de datos, uno para realizar consultas y otro para generar el reporte

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 325


Los botones se llamaran btnReporte y btnConsulta respectivamente

Después agregaremos un nuevo formulario, al que llamaremos frmReporte, y dentro de


este agregaremos un CrystalReportViewer, que tendrá como nombre crvMiReporte

Ahora tenemos que agregar un nuevo componente Crystal Report (Project->add New
Item) y lo llamaremos rptAlumnos

Después de esto nos aparecerá un cuadro de diálogo para seleccionar la forma en la que
queremos crear nuestro reporte. Escogeremos la opción de Using the Report Wizard

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 326


A continuación, debemos seleccionar la base de datos que queremos mostrar en nuestro
reporte. Para esto iremos a la opción Create New Connection->Access/Excel(DAO) y
debemos indicar la ruta de la base de datos.

Posteriormente seleccionaremos la o las tablas que queremos agregar y los campos que
queremos que aparezcan en el reporte

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 327


Después de esto podemos seleccionar otras opciones como por cual campo queremos
agrupar los registros y el estilo del reporte.

Ahora vamos a la parte del código. Primeramente, vamos a implementar la parte de


consultas dentro del evento clic del botón de consultas.

Private Sub btnConsulta_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)


Handles btnConsulta.Click
dt = con.ejecutaSql("SELECT * FROM usuarios WHERE usuario = '" + txtUsuario.Text + "'")
data.DataSource = dt
End Sub

Este código sólo realiza consultas de acuerdo al valor colocado en el txtUsuario (nombre
del usuario).

Ahora, debemos mostrar los resultados de la consulta en el reporte, para esto


agregaremos el siguiente código en el evento clic del del botón Reporte (btnReporte)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 328


Private Sub btnReporte_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles btnReporte.Click
Dim rpt As New rptAlumnos
rpt.SetDataSource(dt)
frmReporte.crvMiReporte.ReportSource = rpt
frmReporte.Show()
End Sub

Y con esto ya tendremos nuestro reporte generado

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 329


8.- Formularios de interfaz múltiple (MDI)
8.1.-Aplicaciones de estilo SDI
Una aplicación de tipo o estilo SDI (Single Document Interface), Interfaz de Documento
Sencillo, está compuesta fundamentalmente de un único formulario, a través del cual,
el usuario realiza toda la interacción con el programa. Como ejemplos de este tipo de
aplicación tenemos el Bloc de Notas o la Calculadora de Windows.
Un programa SDI puede tener más de un formulario, aunque no sea algo habitual. Cuando
eso ocurre, los formularios se ejecutan independientemente, sin un elemento contenedor que
los organice.
8.2.-Aplicaciones de estilo MDI
Una aplicación de tipo o estilo MDI (Multiple Document Interface), Interfaz de Documento
Múltiple, se compone de un formulario principal, también denominado formulario MDI,
que actuará como contenedor de otros formularios (documentos) abiertos durante el
transcurso del programa, denominados formularios hijos o secundarios MDI. Como
ejemplos de este tipo de aplicación tenemos PowerPoint o Access.
A diferencia de lo que ocurría en versiones anteriores de VB, un formulario MDI admite
los mismos controles que un formulario normal, aunque dada su orientación de
formulario contenedor, se recomienda limitar los controles en un MDI a los estrictamente
necesarios. El menú es el ejemplo más identificativo de control idóneo para un formulario
MDI, ya que a través de sus opciones, podremos abrir los formularios hijos de la
aplicación.
Seguidamente describiremos el proceso de creación de un proyecto que contenga un
formulario MDI y dos formularios hijos, así como el comportamiento de estos últimos
cuando son abiertos dentro del formulario padre MDI.
Una vez creado el nuevo proyecto, cambiaremos el nombre del formulario por defecto a
frmPrincipal. Para conseguir que este formulario tenga el comportamiento de un contenedor
MDI, debemos asignar el valor True a su propiedad IsMdiContainer. También debemos
establecer a este formulario como inicial en las propiedades del proyecto.
Ahora pasaremos a la creación de los formularios hijos del MDI. El primero, frmCarta,
permite la escritura en un TextBox multilínea, cuyo contenido podremos grabar a un archivo
en disco. La Figura muestra este formulario.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 330


Formulario hijo de MDI para escribir un texto largo.
El código del botón que realiza la grabación del texto lo podemos ver en el Código
fuente . Debemos importar el espacio de nombres System.IO, ya que en esta clase del
formulario hacemos uso de los tipos File y StreamWriter.
Private Sub btnGrabar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnGrabar.Click
' escribir en un archivo el contenido del TextBox
Dim oEscritor As StreamWriter
oEscritor = File.CreateText(Me.txtArchivo.Text)
oEscritor.Write(Me.txtCarta.Text)
oEscritor.Close()

End Sub
El otro formulario hijo, frmInfo, muestra la fecha y hora actual; esta última es actualizada
a través del control Timer tmrTiempo. Ver la Figura

Formulario hijo de MDI para mostrar fecha y hora actuales.


El Código fuente muestra las instrucciones que se ejecutan en el evento Tick del control

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 331


Timer.
Private Sub tmrTiempo_Tick(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles tmrTiempo.Tick

Dim dtFecha As Date


dtFecha = DateTime.Today
Dim dtHora As Date
dtHora = DateTime.Now
Me.lblFecha.Text = dtFecha.ToString("d/MMM/yyyy")
Me.lblHora.Text = dtHora.ToString("h:m:s")

End Sub
El siguiente paso consiste en crear un menú para poder abrir los formularios hijos a
través de sus opciones. Ver Figura

Menú del formulario MDI.


En las opciones Carta e Información del menú, instanciaremos un objeto del
formulario correspondiente, teniendo en cuenta que para conseguir que dichos
formularios se comporten como hijos del MDI, debemos asignar a su propiedad
MdiParent, la instancia actual del formulario en ejecución, es decir, Me. Veamos este
punto en el Código fuente
Private Sub mnuCarta_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuCarta.Click
Dim ofrmCarta As New frmCarta()
' con la siguiente línea conseguimos que el
' formulario se comporte como hijo del actual
ofrmCarta.MdiParent = Me
ofrmCarta.Show()
End Sub
Private Sub mnuInformacion_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuInformacion.Click
Dim ofrmInfo As New frmInfo()
' con la siguiente línea conseguimos que el
' formulario se comporte como hijo del actual
ofrmInfo.MdiParent = Me
ofrmInfo.Show()
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 332


En la Figura mostramos el formulario MDI en ejecución, conteniendo a los
formularios hijos dependientes.

Aplicación MDI en
ejecución.
8.3.- Creación de menús de tipo Ventana, en formularios MDI
Es probable que el lector haya observado, en algunas aplicaciones Windows de tipo MDI,
que existe en la barra de menús de la ventana principal, un menú con el nombre Ventana o
Window (depende del idioma del programa), que nos muestra los nombres de los formularios
hijos abiertos, permitiéndonos cambiar de formulario activo al seleccionar una de esas
opciones.
n nuestras aplicaciones MDI también podemos disponer de un menú de este tipo,
añadiendo una nueva opción al menú principal del formulario MDI, y asignando a su
propiedad MdiList el valor True.
Adicionalmente, y para darle un aspecto más profesional a este menú, podemos añadir
los MenuItem correspondientes a la organización de los formularios hijos en Cascada,
Mosaico Horizontal, etc. Para organizar los formularios abiertos en la aplicación en
alguno de estos modos, deberemos ejecutar el método LayoutMdi( ) del formulario
MDI, pasándole como parámetro uno de los valores correspondiente a la
enumeración MdiLayout. El Código fuente muestra las opciones correspondientes
a la organización en cascada y en mosaico horizontal de nuestro ejemplo.
Private Sub mnuCascada_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuCascada.Click
Me.LayoutMdi(MdiLayout.Cascade)
End Sub
Private Sub mnuHorizontal_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuHorizontal.Click
Me.LayoutMdi(MdiLayout.TileHorizontal)
End Sub
La Figura muestra el mencionado menú Ventana de este proyecto, en cual contiene en
este caso los nombres de los formularios abiertos que acaban de ser organizados en mosaico
vertical.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 333


Menú ventana en formulario MDI.
8.4.-Bloqueo de opciones de menú en formularios MDI
En la aplicación de ejemplo que estamos desarrollando, podemos abrir tantas copias de los
formularios hijos como necesitemos.
Respecto al formulario que nos permite escribir un texto para grabar a un archivo, es útil
poder tener varios formularios de este tipo, ya que podemos trabajar con diversos archivos a
la vez.
Del formulario hijo que muestra la fecha y hora actual sin embargo, tener más de una copia
no parece algo muy lógico, ya que se trata simplemente de disponer de una información
visualizada, y repetirla a través de la apertura de varios formularios iguales no tiene mucho
sentido.
Para conseguir que de un determinado formulario hijo sólo podamos abrir una instancia,
debemos hacer dos cosas: en primer lugar, en el manipulador de evento correspondiente
a la opción de menú que abre dicho formulario, asignaremos False a la propiedad True
de la mencionada opción de menú. Veámoslo en el Código fuente
Private Sub mnuInformacion_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuInformacion.Click

' deshabilitamos esta opción de menú


Me.mnuInformacion.Enabled = False ' <-----
Dim ofrmInfo As New frmInfo()
' con la siguiente línea conseguimos que el
' formulario se comporte como hijo del actual
ofrmInfo.MdiParent = Me
ofrmInfo.Show()
End Sub
En segundo lugar, dentro del código del formulario hijo, en nuestro caso frmInfo, debemos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 334


escribir el manipulador para el evento Closed del formulario. Este evento se produce
cuando se ha cerrado el formulario, por lo que desde aquí volveremos a activar la opción
de menú del formulario padre, que habíamos deshabilitado.
Para acceder desde un formulario hijo a su MDI contenedor, disponemos de la propiedad
MdiParent, que nos devuelve una referencia de dicho formulario padre. Observe el lector
en el Código fuente cómo además de utilizar la mencionada propiedad, la potencia de la
función CType( ) nos permite en una sola línea de código, llevar a cabo esta acción.
' al cerrar este formulario, activamos de nuevo
' la opción de menú del formulario padre que
' permite crear instancias de este formulario
Private Sub frmInfo_Closed(ByVal sender As Object, ByVal e As System.EventArgs)
Handles MyBase.Closed
' utilizando la función CType(), moldeamos
' la propiedad MdiParent del formulario al tipo
' correspondiente a la clase del formulario MDI;
' con ello obtenemos acceso a sus miembros, y en
' particular a la opción de menú que necesitamos habilitar
CType(Me.MdiParent, frmPrincipal).mnuInformacion.Enabled = True
End Sub
La Figura muestra el resultado al ejecutar. Mientras que el formulario de información esté
abierto, su opción de menú en el MDI estará deshabilitada.

Opción de formulario hijo deshabilitada.


8.5.-Recorrer los formularios hijos de un MDI
La clase Form tiene la propiedad MdiChildren, que devuelve un array con todos los
formularios hijos abiertos hasta el momento.
Esto nos permite recorrer todo este conjunto de formularios para realizar operaciones con
alguno de ellos o todos.
El Código fuente muestra un ejemplo de uso de esta propiedad, en el que mostramos el
título de cada formulario hijo, y además, cambiamos su color de fondo.
Dim oFormHijos() As Form
oFormHijos = Me.MdiChildren

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 335


Dim oForm As Form
For Each oForm In oFormHijos
MessageBox.Show("Título de ventana: " & oForm.Text)
oForm.BackColor = Color.Beige
Next

8.6.- Comportamiento No Modal (Modeless) de formularios


Un formulario de comportamiento no modal, permite el libre cambio de foco entre
el resto de formularios de la aplicación.
Una clara muestra la hemos visto en el proyecto de ejemplo realizado durante los últimos
apartados del texto. En dicha aplicación, podíamos abrir varios formularios hijos dentro
del formulario MDI principal, y pasar de uno a otro sin restricciones.
Otra característica de los formularios no modales reside en que una vez creados y
visualizados, el resto del código de la aplicación continúa su ejecución. Ver Código fuente
Dim ofrmCarta As New frmCarta()
' crear formulario hijo de un mdi
ofrmCarta.MdiParent = Me
ofrmCarta.Show()
' después de mostrar el formulario hijo se muestra a continuación este mensaje
MessageBox.Show("Se acaba de abrir un formulario hijo")

8.7.- Modal de formularios


Como contrapartida al anterior apartado tenemos los formularios de comportamiento modal,
también denominados cuadros o ventanas de diálogo.
Un formulario modal, al ser visualizado, bloquea el paso a otros formularios de la aplicación
hasta que no es cerrado (aceptado o completado) por el usuario.
Como ejemplo de estos formularios se acompaña el proyecto FormDialogos, del que
pasamos a describir su proceso de creación.
Este proyecto contiene un formulario MDI llamado frmPrincipal, y uno hijo con el
nombre frmHijo, que abrimos mediante una opción de menú; la creación de este tipo de
formularios se ha descrito en apartados anteriores.
A continuación añadimos un nuevo formulario al proyecto con el nombre frmDialogo,
que también abriremos a través de la correspondiente opción de menú del formulario
MDI.
Para que este formulario tenga un comportamiento modal, debemos mostrarlo ejecutando
el método ShowDialog( ) de la clase Form. En el Código fuente 505 tenemos las
instrucciones necesarias. Observe también el lector, cómo hasta que el formulario de
diálogo no es cerrado, no se mostrará el mensaje que hay a continuación de la llamada
a ShowDialog( ). Si además intentamos pasar al formulario hijo, en el caso de que esté
abierto, no podremos.
Private Sub mnuDialogo_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuDialogo.Click
' instanciar el formulario que mostraremos como un diálogo
Dim ofrmDialogo As New frmDialogo()
' dar una posición al formulario
ofrmDialogo.StartPosition = FormStartPosition.CenterParent

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 336


' mostrarlo de forma modal, como cuadro de diálogo
ofrmDialogo.ShowDialog()
MessageBox.Show("Se ha cerrado el diálogo")
End Sub
Para cerrar un formulario modal podemos, al igual que para cualquier formulario, ejecutar
su método Close( ). No obstante, un formulario de diálogo suele proporcionar, aunque
esto no es obligatorio, los típicos botones para aceptar, cancelar, reintentar, etc.; de modo
que una vez cerrado el formulario, podamos averiguar qué botón pulsó el usuario.
Podemos proporcionar este comportamiento en nuestros formularios modales,
asignando a la propiedad DialogResult de la clase Form, uno de los valores del tipo
enumerado DialogResult. Esto tendrá como efecto adicional el cierre del cuadro de
diálogo.
Por lo tanto, vamos a añadir a nuestro formulario frmDialogo, dos controles Button:
btnAceptar y btnCancelar, en los que escribiremos las instrucciones del Código fuente
Private Sub btnAceptar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnAceptar.Click
' asignar un valor a esta propiedad, cierra al mismo tiempo el formulario
Me.DialogResult = DialogResult.OK
End Sub
Private Sub btnCancelar_Click(ByVal sender As Object, ByVal e As
System.EventArgs)
Handles btnCancelar.Click
' asignar un valor a esta propiedad, cierra al mismo tiempo el formulario
Me.DialogResult = DialogResult.Cancel
End Sub
Como ayuda en la construcción de formularios modales de diálogo, la clase Form
dispone de las propiedades AcceptButton y CancelButton, a las que podemos asignar
sendos controles Button que serán ejecutados al pulsar las teclas [INTRO] y [ESCAPE]
respectivamente.
Esto es lo que haremos en el formulario frmDialogo, asignando a AcceptButton el control
btnAceptar, y en CancelButton asignaremos btnCancelar.
Finalmente, en el evento de la opción de menú que abre este formulario modal,
correspondiente a frmPrincipal, añadiremos, tras la llamada a ShowDialog( ), el código
que comprobará el resultado de la ejecución del formulario de diálogo. Ver el Código
fuente
Private Sub mnuDialogo_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuDialogo.Click
' instanciar el formulario que mostraremos como un diálogo
Dim ofrmDialogo As New frmDialogo()
' dar una posición al formulario
ofrmDialogo.StartPosition = FormStartPosition.CenterParent
' mostrarlo de forma modal, como cuadro de diálogo
ofrmDialogo.ShowDialog()
' comprobar lo que ha hecho el usuario en el cuadro de diálogo
Dim Resultado As DialogResult
Resultado = ofrmDialogo.DialogResult
If Resultado = DialogResult.OK Then

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 337


MessageBox.Show("Datos del diálogo: " & _
ofrmDialogo.txtNombre.Text & " " & _
ofrmDialogo.txtApellidos.Text)
Else
MessageBox.Show("Se ha cancelado el diálogo")
End If
End Sub
La Figura muestra el programa en ejecución. Como puede comprobar el lector, el
formulario modal, debido a su comportamiento, no se encuentra limitado a los bordes del
formulario MDI; pero depende de este último, ya que si intentamos pasar el foco a un
formulario hijo, no podremos.

Formulario modal de diálogo en ejecución.


8.8.-Controles de cuadros de diálogo del sistema
Del conjunto de controles que nos ofrece la ventana Cuadro de herramientas del IDE,
existe un grupo que nos permite el acceso a los cuadros de diálogo estándar del sistema
operativo, esto es, los cuadros de selección de color, tipo de letra o fuente, apertura-
grabación de archivo, etc.
Para ilustrar el uso de algunos de estos controles, vamos a crear un proyecto de ejemplo con
el nombre DialogosSistema , en el que describiremos su modo de uso en los aspectos de
diseño y codificación.
Crearemos pues, un nuevo proyecto de tipo aplicación Windows, y en su formulario,
insertaremos un menú, añadiendo las siguientes opciones: Abrir, Guardar, Color y
Fuente. Cada opción mostrará un tipo de diálogo del sistema.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 338


Seguidamente insertaremos un TextBox, que acoplaremos con la propiedad Dock a todo el
espacio del formulario, y que nos servirá como base para las operaciones a realizar
mediante los controles de diálogo. La Figura 298 muestra el aspecto de este formulario.

Formulario de pruebas para controles de diálogo estándar.


Una vez dibujado un control de cuadro de diálogo en el formulario, dicho control quedará
ubicado en el panel de controles especiales, al igual que sucede con los menús. Para abrir
un control de este tipo en tiempo de ejecución, emplearemos su método ShowDialog( ).
A continuación describiremos cada uno de los controles de diálogo utilizados en este
ejemplo.
ColorDialog
Este control muestra el cuadro de diálogo del sistema para la selección de colores.
Entre sus propiedades podemos destacar las siguientes.
Color. Contiene un tipo de la estructura Color, que nos permite obtener el color
seleccionado por el usuario mediante este cuadro de diálogo, para poder
aplicarlo sobre alguno de los elementos del formulario.
AllowFullOpen. Contiene un valor lógico que permite habilitar y deshabilitar el
botón que muestra el conjunto de colores personalizados del cuadro de diálogo de
selección de colores.
Al seleccionar en el formulario, la opción de menú Color, ejecutaremos el Código fuente
que nos permitirá, utilizando el control dlgColor, de tipo ColorDialog, elegir un
color y aplicarlo a la propiedad BackColor, del control TextBox.

Private Sub mnuColor_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuColor.Click
Me.dlgColor.ShowDialog()
Me.txtTexto.BackColor = Me.dlgColor.Color
End Sub
La Figura muestra esta aplicación con el formulario y el cuadro de selección de color
abiertos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 339


Cuadro de diálogo estándar para selección de colores.
FontDialog
Este control muestra el cuadro de diálogo del sistema para la selección del tipo de fuente.
Entre sus propiedades podemos destacar las siguientes.
Font. Contiene un tipo de la clase Font. Una vez seleccionada una fuente por el
usuario en el cuadro de diálogo, podremos cambiar el fuente de los controles del
formulario.
ShowApply. Contiene un valor lógico que permite mostrar-ocultar el botón
Aplicar, que nos permitirá asignar el tipo de letra sin cerrar el diálogo. Al pulsar este
botón se desencadenará el
evento Apply de este control de diálogo, en el que podremos escribir el código
necesario para
aplicar la nueva fuente seleccionada.
Al seleccionar en el formulario la opción de menú Fuente, ejecutaremos el Código fuente
509 que nos permitirá, utilizando el control dlgFuente, de tipo FontDialog, elegir un tipo
de letra, y aplicarlo a la propiedad Font del control TextBox; con la particularidad de que
el cambio de letra lo haremos tanto al pulsar el botón Aceptar, como Aplicar del cuadro
de diálogo.
' al hacer clic en este menú, mostramos el cuadro de selección de fuente
Private Sub mnuFuente_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuFuente.Click
Me.dlgFuente.ShowApply = True
Me.dlgFuente.ShowDialog()
Me.AplicarFuente()
End Sub
' este método cambia el fuente del TextBox
Private Sub AplicarFuente()
Me.txtTexto.Font = Me.dlgFuente.Font
End Sub
' al pulsar el botón Aplicar del diálogo de
' selección de fuente, se produce este evento
Private Sub dlgFuente_Apply(ByVal sender As Object, ByVal e As
System.EventArgs)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 340


Handles dlgFuente.Apply
Me.AplicarFuente()
End Sub
La Figura muestra el cambio de fuente sobre el texto del formulario.

Cuadro de diálogo del sistema para selección de tipo de letra.

SaveFileDialog
Este control muestra el cuadro de diálogo del sistema, mediante el que escribimos un
nombre de archivo, y elegimos un directorio, sobre el cual grabaremos información.
Es importante precisar que el control no se ocupa del proceso de grabación de datos; su
cometido es el permitirnos navegar por la estructura del sistema de archivos del equipo, y
la selección de un nombre para el archivo a grabar.
Entre las propiedades del control, podemos destacar las siguientes.
Title. Contiene una cadena con el título que aparecerá en el cuadro de diálogo.
InitialDirectory. Ruta inicial que mostrará el control al abrirse.
Filter. Cadena con el tipo de archivos que mostrará el cuadro de diálogo al
navegar por el sistema de archivos. El formato de esta cadena es el
siguiente: NombreArchivo
(*.Extensión)|*.Extensión; pudiendo situar varios filtros separados por el
carácter de barra vertical ( | ).
FilterIndex. Número que corresponde a alguno de los tipos de archivo
establecidos en la propiedad Filter.
FileName. Nombre del archivo en el que se realizará la escritura
DefaultExt. Cadena con la extensión por defecto a aplicar sobre el nombre del
archivo.
CheckFileExists. Valor lógico que nos permite comprobar si el archivo sobre el
que vamos a grabar ya existe.
ValidateNames. Valor lógico que comprobará si el nombre de archivo
proporcionado contiene caracteres especiales, es decir, si se trata de un nombre
válido.
Al seleccionar en el formulario la opción de menú Grabar, ejecutaremos el Código fuente
510, que nos permitirá, utilizando el control dlgGrabar, de tipo SaveFileDialog,

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 341


seleccionar el nombre de un archivo, y grabar el TextBox del formulario sobre el mismo,
mediante un StreamWriter.
Private Sub mnuGuardar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuGuardar.Click
' configurar por código el diálogo de grabación de archivos
Me.dlgGrabar.Filter = "Documento (*.doc)|*.doc|Texto (*.txt)|*.txt"
Me.dlgGrabar.FilterIndex = 2
Me.dlgGrabar.ValidateNames = True
Me.dlgGrabar.ShowDialog() ' abrir el cuadro de diálogo
' si todo es correcto, escribir mediante un objeto Stream
' el contenido del TextBox en el archivo indicado por
' las propiedades del cuadro de diálogo
Dim swEscritor As IO.StreamWriter
swEscritor = New IO.StreamWriter(Me.dlgGrabar.FileName)
swEscritor.Write(Me.txtTexto.Text)
swEscritor.Close()
MessageBox.Show("Texto grabado en archivo")
End Sub
La Figura muestra el cuadro de dialogo de grabación de archivo.

Cuadro de diálogo para la grabación de archivos.


OpenFileDialog
Este control muestra el cuadro de diálogo del sistema, mediante el que seleccionamos un
archivo para poder abrirlo posteriormente, y realizar sobre el mismo operaciones de lectura-
escritura.
Al igual que en el control anterior, la lectura y escritura de información es algo que
deberemos realizar por código, una vez que hayamos elegido el archivo mediante este
cuadro de diálogo
Las propiedades de este control son prácticamente las mismas que las de SaveFileDialog,
con algunas excepciones como las siguientes.
Multiselect. Contiene un valor lógico, que nos permitirá la selección de múltiples
archivos.
ShowReadOnly. Permite mostrar la casilla de verificación para mostrar los

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 342


archivos de sólo lectura.
ReadOnlyChex. Permite obtener y establecer el valor para la casilla de
verificación de sólo lectura del cuadro de diálogo.
Al seleccionar en el formulario la opción de menú Abrir, ejecutaremos el Código fuente
que nos permitirá, utilizando el control dlgAbrir, de tipo OpenFileDialog, seleccionar un
archivo existente, y pasar su contenido al TextBox del formulario, utilizando un
StreamReader.
Private Sub mnuAbrir_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuAbrir.Click
' configurar el cuadro de diálogo por código
Me.dlgAbrir.Title = "Seleccionar archivo a leer"
Me.dlgAbrir.InitialDirectory = "C:\CUBO"
Me.dlgAbrir.Filter = "Código fuente (*.vb)|*.vb|Texto (*.txt)|*.txt"
' abrir el diálogo
Me.dlgAbrir.ShowDialog()
' si se han seleccionado varios archivos mostrar su nombre
If Me.dlgAbrir.FileNames.Length > 1 Then
Dim sArchivo As String
For Each sArchivo In Me.dlgAbrir.FileNames
MessageBox.Show("Archivo seleccionado: " & sArchivo)
Next
End If
' abrir el primer archivo con un Stream
' y volcarlo al TextBox
Dim srLector As New IO.StreamReader(Me.dlgAbrir.FileName)
Me.txtTexto.Text = srLector.ReadToEnd()
End Sub
La Figura muestra este cuadro de diálogo en ejecución

Cuadro de diálogo de apertura de archivos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 343


8.9.-Formularios dependientes
Formularios dependientes y fijos en primer plano
Un formulario dependiente, también denominado owned form, consiste en un formulario
que es abierto por otro, denominado formulario dueño (owner form), permaneciendo ambos
abiertos, sin que el formulario dependiente requiera ser cerrado, en el caso de que
necesitemos pasar el foco al formulario dueño.
No necesitamos ir muy lejos para encontrar un ejemplo de este tipo de formularios, en el
propio IDE de Visual Studio tenemos muchos casos. En la ventana del editor de código,
cuando abrimos la ventana de búsqueda de texto tecleando [CTRL + F], quedan ambas
visibles en todo momento, aunque no efectuemos ninguna búsqueda y el foco lo tengamos en
el editor de código. En este caso, la ventana Buscar es dependiente de la ventana del editor
de código. Ver Figura
Este comportamiento en los formularios contrasta claramente con el que tienen los
formularios de diálogo, en los cuales, hasta que no es cerrado el diálogo, no podemos
retornar el foco a la ventana que abrió el diálogo.
En versiones anteriores de VB, conseguir un formulario con tal funcionamiento era una
ardua tarea, que requería de conocimientos sobre el API de Windows; sin embargo, el nuevo
motor de formularios de la plataforma .NET, nos permite a través de una serie de
propiedades, que la configuración de formularios dependientes sea un trabajo realmente fácil
y rápido de conseguir.

Editor de código de Visual Studio con ventana de búsqueda.


Por otra parte, un formulario fijo en primer plano, también denominado topmost form,
consiste en un formulario que siempre aparece en primer plano respecto al resto de
formularios de la aplicación. Se trata de una ligera variación de comportamiento respecto
al formulario dependiente; mientras que este último, en algunas ocasiones puede ser
tapado por otros formularios del programa, un formulario topmost siempre permanece
visible en primer plano.
Para ilustrar el modo de creación y funcionamiento de este tipos de formularios, se
acompaña el proyecto de ejemplo FormDependiente , del que comentaremos los
pasos principales para su creación.
Una vez creado este proyecto, eliminaremos su formulario por defecto, y añadiremos el

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 344


formulario frmPrincipal, que configuraremos como contenedor MDI, y al que
añadiremos un menú que nos permitirá abrir un formulario hijo para escribir un texto,
y otro de diálogo para mostrar un literal. La Figura 304 muestra esta ventana MDI de la
aplicación.

Formulario MDI para el ejemplo con formularios dependientes.


El siguiente paso consistirá en crear el formulario frmCarta, que utilizaremos para
abrir los formularios dependientes que crearemos posteriormente en este proyecto. La
Figura muestra este formulario.

Formulario para escribir un texto y abrir formularios dependientes.


El Código fuente muestra el código del menú de frmPrincipal que instancia este
objeto y lo muestra como formulario hijo del MDI.
Private Sub mnuCarta_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuCarta.Click
' este formulario se abre como hijo del MDI
Dim ofrmCarta As New frmCarta()
ofrmCarta.MdiParent = Me
ofrmCarta.Show()
End Sub
A continuación agregaremos al proyecto el formulario frmBuscar. Este formulario

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 345


actuará como dependiente de frmCarta, permitiéndonos buscar una cadena en el TextBox
de este último. La Figura muestra el aspecto de frmBuscar. Aunque no sería necesario,
para adaptarlo mejor a su funcionamiento, hemos variado mediante la propiedad
FormBorderStyle, el estilo de su borde a ventana de herramientas con el valor
FixedToolWindow.
Para conseguir que frmBuscar se comporte como formulario dependiente, al pulsar dentro de
frmCarta el botón Buscar, instanciaremos un objeto frmBuscar, añadiéndolo a la
colección de formularios dependientes de frmCarta mediante el método AddOwnedForm(
), de la clase Form. El Código fuente muestra el código del botón Buscar en el formulario
frmCarta.

Formulario dependiente frmBuscar.


Private Sub btnBuscar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnBuscar.Click
' crear un objeto frmBuscar
Dim ofrmBuscar As New frmBuscar()
' establecer dependencia entre forms
Me.AddOwnedForm(ofrmBuscar)
ofrmBuscar.Show()
End Sub
Podemos eliminar la asociación entre un formulario propietario y uno dependiente
mediante el método RemoveOwnedForm( ) en el formulario propietario. Esto no
quiere decir que el formulario dependiente sea eliminado, simplemente se elimina su
dependencia con respecto al propietario.
En lo que respecta al código de frmBuscar, al pulsar su botón Buscar, buscamos el
contenido del control txtBuscar en el formulario propietario frmCarta.
Si la búsqueda tiene éxito, seleccionamos el texto encontrado dentro del propietario.
La propiedad Owner del formulario nos devuelve una referencia del propietario, mientras
que para manipular los controles de dicho propietario, realizaremos un moldeado de
tipo o type casting sobre Owner utilizando la función CType( ) (observe el lector
de nuevo, la enorme potencia que encierra esta función).
Además mostramos una etiqueta en el formulario dependiente, que sólo se visualizará al
localizar el texto; cuando volvamos a escribir de nuevo texto a buscar, se ocultará dicha
etiqueta. El Código fuente muestra los métodos de frmBuscar que llevan a cabo estas
labores.
' al pulsar este botón, buscamos en el formulario
' propietario de este dependiente

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 346


Private Sub btnBuscar_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnBuscar.Click
Dim iResultadoBuscar As Integer
' la propiedad Owner contiene el formulario propietario
iResultadoBuscar = CType(Me.Owner,
frmCarta).txtDocumento.Text.IndexOf(Me.txtBuscar.Text)
' si encontramos el texto buscado...
If iResultadoBuscar > 0 Then
' pasamos el foco al TextBox del formulario propietario
' y seleccionamos el texto encontrado
CType(Me.Owner, frmCarta).txtDocumento.Focus()
CType(Me.Owner, frmCarta).txtDocumento.SelectionStart =
iResultadoBuscar
CType(Me.Owner, frmCarta).txtDocumento.SelectionLength =
Me.txtBuscar.Text.Length
Me.lblEncontrado.Show()
End If
End Sub
' al volver a teclear un valor a buscar, se oculta el Label
Private Sub txtBuscar_TextChanged(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles txtBuscar.TextChanged
Me.lblEncontrado.Hide()
End Sub
La Figura muestra la aplicación con ambos formularios abiertos. El formulario frmCarta
tiene el foco actualmente, pero eso no impide que frmBuscar también permanezca abierto,
para poder pasar a él en cualquier momento.

Formulario propietario y dependiente en funcionamiento.


Un formulario dependiente, aunque se muestra en todo momento encima de su propietario,

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 347


puede ser ocultado por otro formulario de la aplicación. Para demostrarlo, añadiremos al
proyecto el formulario frmDatosUsuario, que se mostrará como cuadro de diálogo,
visualizando un Label en su interior. Ver Figura

Formulario frmDatosUsuario.
El código de la opción de menú de frmPrincipal que abre este formulario se muestra en
el Código fuente
Private Sub mnuUsuario_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuUsuario.Click

' mostrar este formulario como un diálogo


Dim ofrmUsuario As New frmDatosUsuario()
ofrmUsuario.ShowDialog()
End Sub
La Figura muestra como este formulario oculta parcialmente al de búsqueda.

Formulario de diálogo ocultando parte del formulario dependiente.


Para lograr que un formulario se muestre en todo momento por encima del resto de
formularios de la aplicación, hemos de asignar el valor True a su propiedad TopMost;
obtenemos de esta manera, un formulario con estilo de visualización fijo en primer plano.
Ilustraremos este particular añadiendo un nuevo formulario al proyecto, con el nombre
frmPonerColor, en el que asignaremos a su propiedad TopMost el valor True. Ver la Figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 348


Formulario de estilo TopMost.
El Código fuente muestra el código del botón Color de frmCarta, en el que se crea un
formulario frmPonerColor y se visualiza.
Private Sub btnColor_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnColor.Click
' abrir el formulario para poner color al texto
Dim ofrmPonerColor As New frmPonerColor(Me)
ofrmPonerColor.Show()
End Sub
En este momento debemos hacer dos observaciones: en primer lugar, no añadimos el
formulario frmPonerColor a la colección de formularios dependientes del propietario;
en segundo lugar, al instanciar el objeto frmPonerColor, estamos pasando al constructor
de esta clase la referencia del formulario propietario.
La explicación a este modo de proceder la encontramos dentro del código del formulario
dependiente; en donde añadimos dicho formulario, a la lista de formularios dependientes del
propietario, utilizando la propiedad Owner de la clase base Form. Esto tiene el mismo
efecto que usar el método AddOwnedForm( ). El Código fuente 517 muestra el constructor
de la clase frmPonerColor, en donde llevamos a cabo esta operación.
Public Class frmPonerColor
Inherits System.Windows.Forms.Form
'....
' crear un constructor para establecer el formulario propietario
Public Sub New(ByVal frmPropietario As frmCarta)
Me.New()
Me.Owner = frmPropietario
End Sub

Al volver a ejecutar ahora el programa, si abrimos el formulario frmPonerColor y después el


cuadro de diálogo, será el formulario de configuración de color el que prevalezca por encima,
al ser dependiente y TopMost. Ver Figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 349


El formulario TopMost siempre se sitúa encima del resto.
Este formulario será abierto también desde frmCarta, mediante su botón Color, y lo
utilizaremos para cambiar el color del control de texto de frmCarta. El Código fuente
muestra el procedimiento manipulador de evento de los controles RadioButton, en el
que se realiza el cambio de color en el formulario propietario.

' en este método ponemos el color al TextBox del formulario propietario


Private Sub PonerColor(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles rbtMadera.Click, rbtVerde.Click, rbtTurquesa.Click
Dim oColor As Color
If sender Is Me.rbtMadera Then
oColor = Color.BurlyWood
End If
If sender Is Me.rbtVerde Then
oColor = Color.MediumSpringGreen
End If
If sender Is Me.rbtTurquesa Then
oColor = Color.Turquoise
End If
CType(Me.Owner, frmCarta).txtDocumento.BackColor = oColor
End Sub
Para finalizar con los formularios dependientes, debemos indicar que la clase Form
dispone de la propiedad OwnedForms, que contiene una colección con los
formularios dependientes de un formulario que actúe como propietario.
Ya que en este ejemplo es el formulario frmCarta el que se comporta como propietario,
añadiremos un botón con el nombre btnDependientes, que nos permitirá recorrer la
mencionada colección, y hacer, desde el propietario, una manipulación sobre los
formularios dependientes, en el caso de que haya alguno abierto. El Código fuente
muestra el código de este botón.
Private Sub btnDependientes_Click(ByVal sender As System.Object, ByVal e As

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 350


System.EventArgs) Handles btnDependientes.Click
' obtener los formularios dependientes
Dim oFormularios() As Form = Me.OwnedForms
Dim oFormulario As Form
' si existen dependientes...
If oFormularios.Length > 0 Then
' recorrer la colección y manipular los formularios dependientes
For Each oFormulario In oFormularios
Select Case oFormulario.GetType().Name
Case "frmBuscar"
CType(oFormulario, frmBuscar).lblEncontrado.Show()
CType(oFormulario, frmBuscar).lblEncontrado.Text ="¡LOCALIZADO!"
Color.Blue
Case "frmPonerColor"
CType(oFormulario, frmPonerColor).rbtTurquesa.Text = "AZULADO"
CType(oFormulario, frmPonerColor).rbtTurquesa.BackColor =
' con el método PerformClick() de un control, simulamos una pulsación
CType(oFormulario,
frmPonerColor).rbtTurquesa.PerformClick()
End Select
Next
End If
End Sub

9.10.-Validación de controles
Los controles Windows vienen provistos de un potente y flexible sistema de
validación, que nos permitirá comprobar si el usuario introduce los valores adecuados
en un control, de modo que le permitiremos pasar el foco a otro control, u obligarle a
permanecer en el actual hasta que su valor no sea correcto.
En este esquema de validación, los miembros principales de la clase Control que
intervienen son los siguientes.
CausesValidation. Esta propiedad nos permite establecer un valor lógico, de
manera que cuando un control capture el foco, provocará la validación para otro
control del formulario que
la requiera.
Validating. Este evento se produce para que podamos escribir el código de
validación oportuno en un manipulador de evento. El procedimiento manejador de
evento recibe entre sus parámetros un objeto de tipo CancelEventArgs, por lo
que si la validación no es correcta, asignaremos False a la propiedad Cancel de
dicho objeto.
Validated. Este evento se produce en el caso de que la validación haya tenido éxito.
El proyecto de ejemplo ValidarControl (hacer clic aquí para acceder a este ejemplo)
consta de un formulario con tres controles TextBox. Todos tienen el valor True en su
propiedad CausesValidation, y adicionalmente, para el control txtImporte hemos escrito
el procedimiento que actuará como manipulador del evento Validating; con ello
impediremos el paso desde dicho control a los demás hasta que su contenido no sea

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 351


numérico. Si pasamos la validación, se ejecutará en ese caso el código del evento Validated.
Veamos estos manipuladores de evento en el Código fuente
Private Sub txtImporte_Validating(ByVal sender As Object, ByVal e As
System.ComponentModel.CancelEventArgs) Handles txtImporte.Validating
If Not IsNumeric(Me.txtImporte.Text) Then
e.Cancel = True
MessageBox.Show("Se requiere un número")
End If
End Sub

La Figura muestra esta aplicación en funcionamiento, durante la ejecución del


evento de validación.
En el control txtFecha por otro lado, podemos teclear cualquier valor, aunque no sea fecha,
ya que no proporcionamos manipuladores de evento para validar su contenido.
Cuando escribimos código de validación empleando estos miembros de la clase Control
hemos de tener presente el comportamiento, a veces no muy intuitivo, del sistema de
validación para controles en los formularios Windows.

Validación de un control.
Como hemos mencionado anteriormente, cuando la propiedad CausesValidation de
un control contiene True, al recibir el foco dicho control, se provocará el evento de
validación para el control que acaba de perder el foco. Pero si pasamos el foco a un
control en el que CausesValidation contiene False, la validación no se producirá sobre el
control que acaba de perder el foco.

Esto lo podemos comprobar muy fácilmente sobre nuestro proyecto de ejemplo, asignando al
control txtFecha el valor False en su CausesValidation. A partir de ahora, cuando estemos
situados en el control txtImporte, si este no contiene un número, se producirá la validación
si pasamos el foco a txtNombre, pero no se validará si pasamos a txtFecha.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 352


Indice
9.-Streams en .NET página 289
Las clases basadas en stream
Manejar unfichero usando FileStream
Manejar un fichero usando StreamReader y StreamWriter

10.- Colecciones de datos pagina 332


Tipos de colecciones
Tipos de datos de almaceniamiento de las colecciones
Clases bases para crear colecciones personalizadas

11.- GDI+ Sistema gráfico de Windows pagina 342


System.Drawing

12.- Operaciones de entrada y salida (I/O). pagina 368


System.IO
Objetos Stream
Clases TextReader y TextWriter
Manejo de datos binarios

13.- Ensamblados en Visual Basic Pagina 391

14 .-Crear un proyecto de instalación (Setup) Pagina 397

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 353


9.- Stream en .NET
Según hemos comentado en la introducción, los streams (o secuencias o flujos) nos
permiten abstraernos de la forma en que están implementados los procesos de acceso
a los ficheros u otros recursos. Todas las clases que manejan este tipo de flujos de datos
están basadas (directa o indirectamente) en la clase Stream, la cual nos ofrece ciertos
métodos que nos permiten, entre otras cosas, leer y escribir en esos flujos de
información.
Además de poder leer o escribir, también podemos realizar búsquedas o, dicho de otro
modo, podemos movernos a través de esa secuencia de datos. Pero debido a que no todos
los flujos de datos nos permiten realizar todas las operaciones de la clase Stream, existen
ciertas propiedades por medio de las cuales podemos saber si se permiten todas las
operaciones "básicas" que normalmente podremos hacer con los streams. Por ejemplo,
es posible que no podamos leer o escribir en una secuencia o que no podamos cambiar
la posición del "puntero" de lectura o escritura. Para todas estas comprobaciones
podremos usar las propiedades CanRead, CanWrite o CanSeek, pero creo que antes de
entrar en detalles, deberíamos ver algunos de las clases que .NET pone a nuestra
disposición para poder realizar este tipo de operaciones con "las secuencias" de datos.

Las clases basadas en stream

Entre las clases que están basadas en esta clase abstracta tenemos las siguientes:

BufferedStream, clase abstracta que representa un buffer de almacenamiento para


operaciones de lectura y escritura de otro stream.
DeflateStream, permite la compresión y descompresión de streams usando el algoritmo
Deflat.
GZipStream, usada para comprimir y descomprimir streams.
FileStream, nos permite una forma básica de acceder y manipular ficheros.
MemoryStream, crear un stream que se almacena en la memoria como una secuencia
de bytes.
NetworkStream, proporciona una secuencia de datos para el acceso a la red.
CryptoStream, un stream usado para encriptar otros streams.

Nota:
Las clases DeflateStream y GZipSteam están incluidas en el espacio de
nombres System.IO.Compression.
La clase CryptoStream está incluida en el espacio de nombres

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 354


System.Security.Cryptography.
La clase NetworkStream está incluida en el espacio de nombres
System.Net.Sockets.

Además de estas clases que se derivan directamente de la clase Stream, y que


normalmente se usan como "secuencias" a usar por otras clases de entrada/salida,
tenemos otras que nos permitirán acceder a esas secuencias de datos de una forma más
directa, (algunas de estas las veremos con algo de más detalle en el próximo capítulo
dedicado al sistema de archivos de .NET), por ejemplo:

BinaryReader / BinaryWriter, lee o escribe tipos primitivos como valores binarios


utilizando una codificación específica.
StreamReader / StreamWriter, clases para leer y escribir caracteres en ficheros
utilizando una codificación determinada.
StringReader / StringWriter, implementa TextReader o TextWriter para leer o escribir
en una cadena.
TextReader / TextWriter, clases abstractas para leer o escribir en una secuencia de
caracteres.

Cuando trabajamos con los streams debemos olvidarnos de las "cosas simples" y
debemos tener en cuenta que trataremos casi siempre con secuencias de bytes, ya que
al fin y al cabo esa es la forma de almacenar la información en los streams. Por tanto
cuando veamos los ejemplos que la documentación de Visual Basic 2010 nos
proporciona no debemos extrañarnos de que haya que hacer tantas "cosas" para
acceder o manipular la información almacenada en esas "secuencias" de datos. Si bien,
esa "complicación" nos da mayor control sobre el formato de la información contenida
en los streams. Por suerte, para los que nos gustan las cosas "simples" las clases
específicas nos facilitan mucho las cosas.

A continuación veremos un par de ejemplos en los que manipularemos cierta


información tanto en la memoria usando un objeto del tipo MemoryStream, como en un
fichero de disco usando FileStream y las clases que casi con seguridad usaremos
habitualmente para acceder al contenido de los ficheros: StreamReader y StreamWriter.

Manejar un fichero usando FileStream

En este primer ejemplo veremos lo complicado que pude parecer acceder a un fichero

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 355


usando la clase FileStream y por extensión cualquier método de otras clases que
devuelvan este tipo de secuencia, como por ejemplo los métodos OpenRead,
OpenWrite, etc. de la clase File.

La "complejidad" de esta clase es que realmente obtiene o guarda la información por


medio de un array de tipo Byte, cuando a lo que estamos acostumbrados es a usar
cadenas.

Nota:
Realmente, esta forma "binaria" de acceder a la información de un fichero
no la tenemos que ver como un inconveniente, ya que nos puede servir para acceder de
forma "binaria" a ese fichero, en caso de que nuestra intención sea acceder de forma
"normal" para, por ejemplo, leer solo texto, deberíamos usar otras clases más
especializadas para esa tarea, como lo es StreamReader.

En el siguiente código tenemos dos métodos, uno que guarda una cadena en el
fichero indicado:

Private Sub guardarDatos(ByVal fichero As String, ByVal cadena As String)


' Abrimos o creamos el fichero, para escribir en él

Dim fs As New
System.IO.FileStream(fichero, _
System.IO.FileMode.OpenOrCreat
e, _ System.IO.FileAccess.Write)
' Escribimos algunas cadenas,
' el problema es que solo podemos escribir arrays de bytes,
' por tanto debemos convertir la cadena en un array de bytes
Dim datos() As Byte
' pero usando la codificación que creamos conveniente
' de forma predeterminada es UTF-8,
' aunque la codificación de Windows es ANSI (Encoding.Default)
Dim enc As New System.Text.UTF8Encoding
' convertimos la cadena en un array de bytes
datos = enc.GetBytes(cadena)
' lo escribimos en el stream
fs.Write(datos, 0,
datos.Length)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 356


' nos aseguramos que se escriben todos los
datos fs.Flush()
' cerramos el stream
fs.Close()
End Sub

En el constructor de la clase FileStream indicamos el fichero en el que queremos


guardar la información, también le indicamos que queremos crearlo o abrirlo, es
decir, si ya existe lo abre y si no existe lo crea, de cualquiera de las formas, en el
siguiente parámetro del constructor le indicamos que nuestra intención es escribir
en ese fichero.
Como hemos comentado, la clase FileStream (y en general todos los streams)
trabaja con bytes, por tanto para poder almacenar algo en ese fichero debemos
hacerlo mediante un array de tipo Byte.
En el caso de las cadenas, éstas siempre deben estar codificadas, es decir, deben usar
el juego de caracteres que creamos conveniente, en el mundo de .NET ese juego de
caracteres es Unicode, más concretamente usando la codificación UTF-8, la cual
permite trabajar con cualquier carácter de cualquier cultura.
Como lo que nos interesa es convertir una cadena en un array de bytes, usamos
el método GetBytes de un objeto UTF8Encoding, el cual convierte la cadena en
una "ristra" de bytes con el formato adecuado, en este caso UTF-8.
Si en lugar de usar UTF-8 quisiéramos usar otro "codificador", por ejemplo el
predeterminado de Windows, con idea de que los ficheros sean compatibles con
otras aplicaciones que utilizan el formato predeterminado de Windows,
tendremos que declarar la variable enc de la siguiente forma:

Dim enc As System.Text.Encoding = System.Text.Encoding.Default


A continuación, simplemente le pasamos el array de bytes al método Write del
FileStream indicando desde que posición de dicho array debe escribir y cuantos
bytes. Por último nos aseguramos de que todos los bytes del "buffer" se guarden en
el fichero y lo cerramos.

Y otra función que devuelve el contenido de un fichero en formato cadena:

Private Function leerDatos(ByVal fichero As String) As String


' Los bloques leídos los almacenaremos en un StringBuilder
Dim res As New System.Text.StringBuilder
' Abrimos el fichero para leer de él

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 357


Dim fs As New System.IO.FileStream(fichero, _
System.IO.FileMode.Open, _
System.IO.FileAccess.Read)
' los datos se leerán en bloques de 1024 bytes (1 KB) Dim
datos(1024) As Byte
Dim enc As New System.Text.UTF8Encoding()
' leemos mientras hay algo en el fichero
While fs.Read(datos, 0, 1024) > 0

' agregamos al stringBuilder los bytes leídos


' (convertidos en una cadena)
res.Append(enc.GetString(datos))
End While
' cerramos el
buffer
fs.Close()
' devolvemos todo lo leído
Return res.ToString
End Function
En esta función vamos a leer los datos del fichero indicado, como ya hemos vistos,
la clase FileStream trabaja con bytes y esos bytes los convertimos a caracteres por
medio de las clases de codificación especializadas.
Por regla general, esas lecturas las haremos de forma parcial, es decir leyendo
bloques de bytes y como tenemos que convertir esos bytes en caracteres, y puede
ser que el fichero sea muy grande, en lugar de concatenar una cadena para
almacenar las lecturas parciales, vamos a usar un objeto del tipo StringBuilder en el
que iremos "agregando" cada trozo leído, de forma que el rendimiento no se vea
penalizado por la forma de ser de las cadenas, ya que cada vez que hacemos una
concatenación en una variable de tipo String, realmente estamos creando nuevos
objetos en la memoria y si son muchos, pues la verdad es que tendremos al
recolector de basura (GC) trabajando a tope, y si usamos un objeto StringBuilder el
rendimiento mejora una barbaridad.
La lectura de cada bloque de bytes lo hacemos en un bucle While, también
podríamos haberlo hecho en un bucle Do While, pero en estos casos, el
rendimiento de While es un "poquitín" mayor.
Los datos leídos los agregamos al objeto StringBuilder por medio del método Append
que se encarga de agregarlo a la cadena interna.
Finalmente cerramos el stream y devolvemos la cadena leída.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 358


Para usar estas dos funciones lo podemos hacer de la siguiente forma:

' un fichero de ejemplo (el directorio debe existir) Const fichero As


String = "E:\Pruebas\prueba.txt"
' guardamos una cadena en el fichero guardarDatos(fichero, "Hola, Mundo de
FileStream")
'
' Leemos el contenido del fichero y lo mostramos
Console.WriteLine(leerDatos(fichero))

Este código no necesita mayor explicación.

Manejar un fichero usando StreamReader y StreamWriter

A continuación veremos cómo crear las dos funciones del ejemplo anterior para que
utilicen las clases "especializadas" para leer y escribir cadenas en un fichero.
Como podremos comprobar, esta es una forma muchísimo más simple y, por tanto
recomendada para este tipo de acceso a los ficheros. Aunque debemos recordar que
solo servirá para leer la información de forma secuencial y en formato cadena.

Nota:
El código para usar estas dos funciones será el mismo que el usado para las funciones
que utilizan la clase FileStream.

La función para guardar una cadena en un fichero:

Private Sub guardarDatos(ByVal fichero As String, ByVal cadena As String)


' Abrimos el fichero para escribir, (no añadir),
' usando la codificación predeterminada: UTF-8
Dim sw As New System.IO.StreamWriter(fichero, False)
' guardamos toda la cadena
sw.WriteLine(cadena)
' Cerramos el fichero sw.Close()
End Sub

Como podemos apreciar, esta es una forma mucho más "compacta" que la anterior, ya

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 359


que solo tenemos que indicar en el constructor lo que queremos hacer y usar el
método Write o WriteLine para guardar lo que queramos en el fichero.

Para guardarlo usando la codificación predeterminada del Sistema Operativo en el que


se utilice la aplicación, (en Windows será ANSI), simplemente usamos este constructor:

Dim sw As New System.IO.StreamWriter(fichero, False,


System.Text.Encoding.Default)

Para leer los datos podemos hacerlo de dos formas: línea a línea o todo el
contenido de una sola vez.
En el código siguiente se muestra línea a línea, y al final, (comentado), cómo
hacerlo en una sola pasada.

Private Function leerDatos(ByVal fichero As String) As String


' Abrimos el fichero para leer
' usando la codificación UTF-8 (la predeterminada
de .NET) Dim sr As New
System.IO.StreamReader(fichero, True)
' si queremos usar la predeterminada de Windows
'Dim sr As New System.IO.StreamReader(fichero,
System.Text.Encoding.Default)
' Podemos leer cada una de las líneas del fichero o todo el contenido
' Forma larga:
' si vamos a leer el fichero línea por línea, mejor usar un StringBuilder
Dim ret As New System.Text.StringBuilder
' recorremos el fichero hasta que no haya nada que leer
While sr.Peek <> -1
ret.Append(sr.ReadLine)
End While
' cerramos el fichero
sr.Close()
' devolvemos lo leído
Return ret.ToString
'
'' Forma corta:
'' leemos todo el contenido del fichero
'Dim ret As String = sr.ReadToEnd()

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 360


'' lo cerramos
'sr.Close()
'' devolvemos lo leído
'Return ret
End Function

Si nos decidimos a leer el contenido del fichero línea a línea, podemos usar el método
Peek, el cual devolverá el siguiente carácter del buffer del stream, o -1 si no hay nada
que leer. Peek no "consume" el carácter, simplemente comprueba si hay algo que leer.
Si hay algo que leer, leemos la línea completa y la añadimos al objeto StringBuilder, el
bucle se repetirá mientras haya información pendiente de leer.

Pero si optamos por la vía rápida, porque realmente no nos interese procesar cada línea,
podemos usar el método ReadToEnd, que en nuestro ejemplo, el valor devuelto será todo
el contenido del fichero, el cual asignamos a una variable de tipo String para usarla como
valor devuelto por la función, después de cerrar el fichero.

Asegurarnos que el fichero se cierra

Si queremos ahorrarnos el paso intermedio de asignar el valor en una variable y


después devolverlo, también podemos hacerlo de esta forma:
Try
Return sr.ReadToEnd()
Finally
sr.Close()
End Try
Ya que el bloque Finally siempre se ejecutará, se produzca o no un error, por tanto nos
aseguramos de que el fichero se cierra.

Liberar recursos: Using... End Using

O si lo preferimos, podemos usar la nueva forma de asegurarnos de que los recursos


usados se liberan:

' Podemos usar Using para asegurarnos de que el recurso se libera


Private Function leerDatos(ByVal fichero As String) As String
Dim sr As New System.IO.StreamReader(fichero, True)
Using sr

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 361


Return
sr.ReadToEnd() End
Using
End Function

En este código, cuando usamos Using sr, al ejecutarse End Using, el CLR se encargará de
llamar al método Dispose de la clase, de forma que se liberen los recursos que estemos
usando, en este ejemplo: el fichero abierto.

Estos dos últimos ejemplos serían equivalentes a los anteriores, más seguros, pero
también con más "trabajo" para el CLR.

Nota:
Using... End Using solo se puede usar con clases que implementen la interfaz IDisposable,
que es la que asegura que el objeto implementa el método Dispose.

Por tanto, si implementamos el método IDisposable.Dispose en nuestras clases, en ese


método nos tenemos que asegurar que liberamos los recursos que nuestra clase esté
utilizando.

Ejemplo de para cifrar y descifrar un fichero

En el siguiente ejemplo (adaptado de uno de la documentación), veremos cómo usar


algunas de las clases basadas en Stream, particularmente las clase MemoryStream,
FileStream, CryptoStream además de las clases StreamReader y StreamWriter.

Este código tiene dos funciones:


La primera encripta (cifra) una cadena y la guarda en un fichero.
La segunda desencripta (descifra) el contenido de un fichero y lo guarda en otro. Ambas
funciones devuelven la cadena cifrada o descifrada respectivamente.

Imports System Imports System.IO


Imports System.Text
Imports System.Security.Cryptography

Module Module1
Const fic1 As String = "E:\Pruebas\Prueba CryptoStream.txt"
Const fic3 As String = "E:\Pruebas\Prueba CryptoStream

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 362


des.txt"
Const sKey As String = "El password a usar"
'
Sub Main()
Dim ret As String
'
ret = cifrarFichero("Hola, Mundo encriptado", fic1)
Console.WriteLine("Cadena encriptada : {0}", ret)
'
ret = descifrarFichero(fic1, fic3) Console.WriteLine("Cadena
desencriptada: {0}", ret)
' Console.ReadLine()
End Sub

Function cifrarFichero( _
ByVal texto As String, _
ByVal ficSalida As String) As String
' Creamos un MemorySream con el texto a cifrar
Dim enc As New UTF8Encoding
Dim datos() As Byte = enc.GetBytes(texto)
Dim ms As New MemoryStream(datos)
' El fichero de salida
Dim fs As New FileStream(ficSalida, FileMode.Create, FileAccess.Write)
' El proveedor criptográfico
Dim r As New DESCryptoServiceProvider
'
' Establecer la clave secreta
r.Key = Encoding.Default.GetBytes(sKey.Substring(0, 8))
r.IV = Encoding.Default.GetBytes(sKey.Substring(0, 8))
'
' Crear una secuencia de cifrado
Dim cs As New CryptoStream(fs,r.CreateEncryptor(), _
CryptoStreamMode.Write)
'
' Escribir el fichero cifrado cs.Write(datos, 0,
datos.Length)
cs.Close()
'

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 363


' devolver el texto cifrado
Return Convert.ToBase64String(ms.ToArray())
End Function

Function descifrarFichero( _
ByVal fichero As String, _
ByVal ficSalida As String) As String
' el proveedor del cifrado y las claves usadas para cifrar
Dim r As New DESCryptoServiceProvider
r.Key() = Encoding.Default.GetBytes(sKey.Substring(0, 8))
r.IV = Encoding.Default.GetBytes(sKey.Substring(0, 8))
'
' crear la secuencia para leer el fichero cifrado
Dim fs As New FileStream(fichero, FileMode.Open, FileAccess.Read)
'
Dim cs As New CryptoStream(fs,r.CreateDecryptor(), _
CryptoStreamMode.Read)
'
' guardar el contenido de fichero descifrado
Dim sw As New StreamWriter(ficSalida) Dim sr As New StreamReader(cs)
sw.Write(sr.ReadToEnd)
sw.Flush()
sw.Close()
'
' devolver el texto
sr = New StreamReader(fic3)
Dim ret As String = sr.ReadToEnd()
sr.Close()
'
Return ret
End Function
End Module

10.- Colecciones en VB.Net

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 364


Colecciones, la especialización de los arrays

A través de la clase Array, podemos manipular estos elementos del lenguaje con una
mayor potencia y flexibilidad que en pasadas versiones del lenguaje. No obstante, en
muchas ocasiones nos encontraremos con situaciones en las que sería muy agradable
que los arrays dispusieran de algunas características adicionales, dependiendo del
problema que tengamos que resolver en ese preciso momento.

Por ejemplo, sería una gran idea poder manejar un array que creciera dinámicamente,
sin tener que preocuparnos por aumentar o disminuir su tamaño; o también, disponer
de un array a cuyos valores pudiéramos acceder, a través de identificadores claves, y
no por el número de índice, que en algunas situaciones es más incómodo de manejar.

Todas las funcionalidades mencionadas, y algunas más, se encuentran disponibles


en un tipo especial de array denominado colección (collection).

Nota:
Diferencia básica entre estos tipos de colecciones es cómo están almacenados los
elementos que contienen, por ejemplo, las colecciones de tipo IList (y las directamente
derivadas de ICollection) solo almacenan un valor, mientras que las colecciones de tipo
IDictionary guardan un valor y una clave relacionada con dicho valor.

Definicion:
Una colección es un objeto que internamente gestiona un array, pero que está
preparado, dependiendo del tipo de colección, para manejar el array que contiene de
una manera especial; podríamos definirlo como un array optimizado o especializado en
ciertas tareas.

El espacio de nombres System.Collections

Este espacio de nombres del entorno de .NET Framework, es el encargado de agrupar el


conjunto de clases e interfaces que nos permiten la creación de los distintos tipos de objetos
collection. Por lo que si necesitamos un array con alguna característica especial, sólo
hemos de instanciar un objeto de alguna de las clases de este espacio de nombres para
disponer de un array con esa funcionalidad. Entre las clases más significativas de
System.Collections, podemos destacar las siguientes.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 365


ArrayList. Proporciona una colección, cuyo array es redimensionado
dinámicamente.

Hashtable. Las colecciones de este tipo, contienen un array cuyos elementos se


basan en una combinación de clave y valor, de manera que el acceso a los valores
se facilita, al realizarse mediante la clave.

SortedList. Consiste en una colección ordenada de claves y valores.

Queue. Representa una lista de valores, en el que el primer valor que entra, es el
primero que sale.

Stack. Representa una lista de valores, en el que el último valor que entra, es el
primero que sale.

Para hacer uso de colecciones en una aplicación VB.NET creada desde VS.NET, no es
necesario importar este espacio de nombres, ya que como sabrá, el propio IDE incluye
por defecto la importación del espacio System al proyecto.

La clave se halla en los interfaces

Las clases integrantes de System.Collections implementan en mayor o menor grado,


un conjunto común de interfaces, que proporcionan la funcionalidad para el trabajo
con arrays especializados o colecciones. Entre alguno de los interfaces de Collections,
podemos mencionar los siguientes.

IEnumerable. Proporciona el soporte para recorrer colecciones de valores.

ICollection. Proporciona las características para manipular el tamaño,


gestionar enumeradores, etc., de listas de valores.

IList. Referencia a una lista de valores que puede ordenarse.

ICloneable. Permite la creación de copias exactas e independientes de objetos.

Todo ello significa, que además de las clases con las funcionalidades especiales de
Collections, podemos crear nuestras propias clases, para aquellos casos en los que
necesitemos disponer de un array con funcionalidades especiales, no contempladas

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 366


por los arrays base, y que además tampoco exista como colección. La manera de crear
nuestro propio tipo de colección sería heredando de una clase collection existente y/o
la implementación de alguno de los interfaces de Collections.

Las colecciones basadas en ICollection

La interfaz ICollection es un caso aparte, ya que realmente todas las colecciones de .NET
implementan esta interfaz, de hecho, esta interfaz se deriva de IEnumerable que es la
que nos permite recorrer las colecciones usando bucles For Each.

Esta interfaz no la tendremos que usar de forma habitual, ya que realmente el resto de
colecciones (e interfaces) útiles ya se derivan de ella, por tanto vamos a centrarnos en
las otras dos.
Aunque es importante que tengamos en cuenta que el resto de colecciones implementan
ICollection, por tanto siempre podremos usar un objeto de este tipo para acceder a
cualquier colección.

Independientemente de que todas las colecciones de .NET estén basadas en esta interfaz,
hay ciertos tipos de colecciones que solo implementan esta interfaz, por ejemplo las
colecciones de tipo Queue, Stack o BitArray, por tanto esas colecciones estarán limitadas
a los métodos expuestos por la interfaz ICollection y los que esas colecciones
implementen de forma independiente.

Por regla general, los tipos que solo se basan en ICollection suelen ser colecciones que no
necesitan de las características que proporcionan las otras interfaces y, por regla general,
nos permiten la manipulación de los datos de una forma básica o elemental, de forma
que su uso sea para casos muy concretos.

Por ejemplo, la clase Queue nos permite crear fácilmente una colección de tipo FIFO
(primero en entrar, primero en salir); por otra parte, con la clase Stack podemos crear
colecciones del tipo LIFO (último en entrar, el primero en salir), de forma que sean muy
útiles para crear "pilas" de datos.

El caso de la otra clase que hemos comentado: BitArray, nos sirve para almacenar valores
de tipo "bit", en el que cada valor se almacena como un cero o un uno, de forma que
podamos tener una colección muy compacta, pero, también muy específica y no de uso
general, ya que en este caso particular, los métodos que implementa esta clase están
enfocados en la manipulación de valores de tipo Boolean, (False y True), aunque

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 367


internamente se almacenen como valores cero y uno respectivamente.

Nota:
Realmente la clase BitArray no se comporta como una colección "normal", ya que el
tamaño de la misma debemos controlarlo nosotros, al igual que ocurre con los arrays,
aunque de forma más "fácil", mediante la propiedad Length.

Las colecciones basadas en IList

La interfaz IList se utiliza en las colecciones a las que queremos acceder mediante un
índice, por ejemplo, los arrays realmente está basados en esta interfaz, y tal como
pudimos comprobar, la única forma que tenemos de acceder a los elementos de un array,
(y por extensión a los elementos de las colecciones basadas en IList), es mediante un
índice numérico.

Existen tres tipos principales de colecciones que implementan esta interfaz:

Las de solo lectura, colecciones que no se pueden modificar. Este tipo de


colecciones suelen basarse en la clase abstracta ReadOnlyCollectionBase.
Las colecciones de tamaño fijo, no se pueden quitar ni añadir elementos,
pero si modificarlos. Por ejemplo, las colecciones basadas en Array son de
tamaño fijo.
Las de tamaño variable permiten cualquier tipo de adición, eliminación y
modificación. La mayoría de las colecciones suelen ser de este tipo, es decir, nos
permiten dinámicamente añadir o eliminar elementos.

Existe un gran número de colecciones en .NET que implementan esta interfaz, (sobre
todo las colecciones basadas en controles), entre las que podemos destacar las
siguientes:

ArrayList, la colección "clásica" para este tipo de interfaz. Contiene todos los
miembros habituales en este tipo de colecciones.
CollectionBase, una clase abstracta para poder crear nuestras propias
colecciones basadas en IList.
StringCollection, una colección especializada que solo puede contener valores de
tipo cadena.

La colección ArrayList

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 368


Tal como hemos comentado, el tipo de colección que se usa como referencia a la hora de
hablar de las colecciones basadas en la interfaz IList, es ArrayList.

Esta colección permite añadir, eliminar y modificar fácilmente los elementos que
contiene. También podemos recorrerlos mediante un bucle For accediendo a los
elementos por medio de un índice e incluso mediante un bucle del tipo For Each.
Al igual que ocurre con los arrays, el índice inferior es siempre el cero y los elementos se
almacenan de forma consecutiva, es decir, si añadimos dos elementos a una colección de
tipo ArrayList (y a las que implementen la interfaz IList), el primero ocupará la posición
cero y el segundo la posición uno. La ventaja de trabajar con las colecciones es que no
debemos preocuparnos de reservar memoria cada vez que vayamos a añadir un nuevo
elemento, simplemente usamos el método Add y asunto arreglado.

Lo mismo ocurre a la hora de quitar elementos de una colección, no tenemos que


preocuparnos demasiado por el espacio dejado al quitar elementos, de eso se encarga el
propio .NET, nosotros simplemente debemos llamar al método Remove o RemoveAt
indicando respectivamente el elemento a eliminar o el índice en el que se encuentra
almacenado.

Truco:
Si decidimos eliminar varios elementos de una colección de tipo IList (o de un array), lo
normal es que lo hagamos usando un bucle For; si este es el caso, para evitar una posible
excepción, (realmente no es posible, sino con toda certeza segura), debemos recorrer el
bucle desde el final hacia adelante, con idea de que al cambiar el número de elementos
no falle al intentar a acceder a un elemento que ya no existe.

El tipo de datos de almacenamiento de las colecciones

Estos elementos internamente están almacenados como objetos del tipo Object, por
tanto podemos añadir cualquier tipo de datos a una colección de este tipo, ya que todos
los tipos de datos de .NET están basado en la clase Object.

El problema con este tipo de colecciones es que siempre que queramos acceder a uno
de los elementos que contiene, debemos hacer una conversión al tipo adecuado, es
decir, si en una colección de este tipo guardamos objetos de tipo Cliente y queremos
acceder a uno de ellos, debemos hacer una conversión (cast) del tipo Object al tipo
Cliente, ya que si no lo hacemos y tenemos activada Option Strict (la opción para las

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 369


comprobaciones estrictas), se producirá un error si hacemos algo como esto:
Dim lista As New
ArrayList lista.Add(New
Cliente("Pepe"))
lista.Add(New
Cliente("Lola"))

Dim unCliente As Cliente


' ¡Error!
unCliente = lista(0)
...
Por tanto, la última línea deberíamos escribirla de una de estas dos formas:

' Usando CType para hacer la


conversión unCliente =
CType(lista(0), Cliente)
...
' Usando DirectCast para hacer la conversión (más recomendable)
unCliente = DirectCast(lista(0), Cliente)

Otro de los problemas que tienen las colecciones "normales" es que en algunos casos,
particularmente cuando almacenamos tipos por valor, el rendimiento se ve bastante
mermado, ya que el runtime de .NET (el CLR) debe hacer lo que en inglés se conoce
como boxing/unboxing, es decir, convertir un tipo por valor en uno por referencia
cuando va a guardarlo en la colección (boxing), y el proceso inverso cuando lo
queremos recuperar (unboxing).

Nota:
Por suerte, en Visual Basic 2010 tenemos otra forma de mejorar el rendimiento de las
colecciones, y es mediante las colecciones "generic", de esto, nos ocuparemos más
adelante.

Otras de las ventajas de las colecciones de .NET, no solo las basadas en la interfaz IList,
es que proporcionan una gran cantidad de métodos que nos facilitan la manipulación de
ese tipo de datos. Por ejemplo, tenemos métodos para clasificar el contenido de las
colecciones, (aunque esos objetos deben implementar la interfaz IComparable, tal como
vimos en el último ejemplo del capítulo de las interfaces), además tienen métodos para
hacer copias, buscar elementos y muchos etcéteras más.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 370


Las colecciones basadas en IDictionary

El otro grupo de colecciones que podemos encontrar en .NET son las colecciones basadas
en la interfaz IDictionary. Éstas, a diferencia de las colecciones IList, siempre mantienen
el par clave/valor, ya que la forma de acceder a los elementos es mediante una clave
única. Por tanto, cada vez que añadimos un elemento a una colección de este tipo
tendremos que indicar una clave y un valor. Cada valor estará relacionado con su
correspondiente clave.

Sabiendo esto, es fácil adivinar que si queremos acceder a un elemento, lo normal es que
lo hagamos usando la clave indicada al añadirlo. Los que hayan trabajado anteriormente
con Visual Basic 6.0, (o lo estén haciendo actualmente), puede que piensen que también
se podrá acceder a cada elemento mediante un índice numérico, ya que el objeto
Collection de VB6, (que aún sigue existiendo en Visual Basic 2010), nos permite indicar
una clave para cada elemento, y además de acceder a esos elementos mediante la clave,
podemos hacerlo mediante un valor numérico (índice). Pero en las colecciones basadas
en IDictionary, salvo casos muy especiales, siempre accederemos a los valores contenidos
mediante la clave y "nunca" mediante un índice que haga referencia a la posición dentro
de la colección, entre otras cosas porque cuando almacenamos valores en este tipo de
colecciones, éstos no se guardan en el mismo orden en que fueron añadidos.

Nota:

Si bien la clase Collection está disponible en la nueva versión de Visual Basic, ésta
tiene algunas mejoras con respecto a la que tiene VB6, entre esas mejoras están dos
nuevos métodos que nos facilitarán su uso: el método Clear con el que podemos
eliminar todos los elementos de la colección y el método Contains, con el que
podemos averiguar si un determinado elemento está en la colección.

Entre las colecciones basadas en la interfaz IDictionary podemos destacar:

Hashtable, es la colección por excelencia de las basadas en IDictionary. Los


elementos se organizan basándose en el código hash de las claves.
DictionaryBase, es una clase abstracta que podemos usar como base de
nuestras propias colecciones de tipo diccionario.
ListDictionary, es una colección con mayor rendimiento que Hashtable pensada
para trabajar con 10 o menos elementos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 371


HybridDictionary, es una colección especial en la que si hay 10 o menos elementos,
se utiliza una colección ListDictionary y si contiene más elementos se utiliza una
colección Hashtable.
SortedList, es una colección en la que los elementos están clasificados por las
claves. Internamente utiliza una mezcla entre Hashtable y Array, según la forma
en que se
accedan a esos elementos.

Almacenar valores en una colección tipo IDictionary

Para añadir nuevos elementos a una colección de tipo IDictionary siempre tendremos
que indicar la clave y el valor, la clave no puede ser un valor nulo, (Nothing), pero puede
ser de cualquier tipo. El valor también puede ser de cualquier tipo y en este caso si que
se admiten valores nulos.

Los elementos los añadiremos usando el método Add, al que habrá que indicar
primero la clave y después el valor:

Dim valores() As String = {"uno", "dos", “tres"} Dim dic As New _


System.Collections.Hashtable
For i As Integer = 0 To valores.Length - 1
dic.Add(valores(i), "El valor de " & valores(i))
Next

Cómo se almacenan los elementos de las colecciones IDictionary

Tal como hemos comentado, las colecciones que implementan la interfaz IDictionary
siempre almacenan un par de datos: la clave y el valor propiamente dicho, por tanto cada
vez que queramos acceder a un valor, debemos usar la clave asociada con dicho valor. Al
menos esa es la forma habitual, ya que como veremos, también podremos acceder a esos
valores directamente.

Debido a esta característica, para acceder a los elementos de este tipo de colecciones
por medio de un bucle del tipo For Each, debemos usar una clase llamada
DictionaryEntry, esta clase tiene dos propiedades, una contiene la clave y otra el valor.
Por tanto, cuando usemos un bucle For Each, el tipo de objeto usado para acceder a los
elementos de la colección será DictionaryEntry, tal como vemos en el siguiente código:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 372


For Each de As DictionaryEntry In dic
Console.WriteLine("{0} = {1}", de.Key, de.Value)
Next

Obtener todas las claves y valores de una colección IDictionary


Independientemente de que podamos recorrer los valores contenidos en una colección
de tipo IDictionary usando un objeto de tipo DictionaryEntry, habrá ocasiones en las que
realmente nos interesen tener solo los valores e incluso solo las claves, en estos casos,
podemos usar dos propiedades que la interfaz IDictionary define: Keys y Values. Estas
propiedades devuelven un objeto del tipo ICollection con las claves y valores
respectivamente.

Al ser objetos ICollection, solo podremos usarlos para recorrerlos por medio de un bucle
For Each, ya que las colecciones ICollection no tienen ningún método que nos permita
acceder a los elementos que contiene usando un índice. En el siguiente código mostramos
todas las claves de la colección creada en el ejemplo anterior:

For Each clave As String In dic.Keys


MsgBox(clave)
Next
Nota:
Siempre que usemos un bucle For Each para recorrer los elementos (o datos) de una
colección, solo tendremos acceso de solo lectura a esos datos, es decir, no podremos
modificarlos usando la variable por medio de la que accedemos a ellos.

Seguidamente realizaremos una descripción general y pruebas con algunas de las


colecciones existentes en el entorno, remitiendo al lector a la documentación de la
plataforma accesible desde Visual Studio .NET para los detalles más específicos.

La clase ArrayList

Los objetos de tipo colección creados con esta clase, implementan un array cuyo número
de elementos puede modificarse dinámicamente.

Instanciación de objetos ArrayList

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 373


Podemos instanciar una colección ArrayList en alguno los modos mostrados en el Código
fuente. Observe el lector, cómo en este ejemplo, el constructor de ArrayList recibe como
parámetro una colección dinámica.

Private Sub Button1.Click….


' crear una lista sin elementos
Dim alEstaciones As New ArrayList()
' crear una lista indicando el número de elementos pero sin darles valor
Dim alDatos As New ArrayList(3)
' crear una lista utilizando una colección dinámica
Dim alLetras As New ArrayList(New String() {"a", "b", "c"})
End Sub

Una colección dinámica se crea de forma muy similar a un array, con la diferencia de
que no es necesario usar una variable a la que asignar la colección, ya que en su lugar, se
pasa como parámetro al constructor de ArrayList. El modo de creación de una colección
dinámica consiste en utilizar la palabra clave New, seguida del tipo de dato de la colección,
los paréntesis indicativos de array, y por último, encerrados entre llaves, los valores de la
colección.

Agregar valores a un ArrayList

Una vez creado un ArrayList, podemos utilizar algunos de los métodos indicados a
continuación para añadir valores a la colección.

Add(Valor). Añade el valor representado por Valor.

AddRange(Colección). Añade un conjunto de valores mediante un objeto del


interfaz ICollection, es decir, una colección dinámica creada en tiempo de ejecución.

Insert(Posición, Valor). Inserta el valor Valor en la posición Posición del array,


desplazando el resto de valores una posición adelante.

InsertRange(Posición, Colección). Inserta un conjunto de valores mediante una


colección dinámica, a partir de una posición determinada dentro del array.

SetRange(Posición, Colección). Sobrescribe elementos en un array con los valores


de la colección Colección, comenzando en la posición Posición.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 374


El siguiente ejemplo muestra algunas formas de asignación de nuevos valores a un
ArrayList.

Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles


Button2.Click
TextBox1.Text = “ “
Dim alDatos As New ArrayList(10)
alDatos.Add("a")
alDatos.AddRange(New String() {"b", "c", "d"})
TextBox1.Text = TextBox1.Text & "ArrayList después de usar Add() y AddRange()" _
& vbCrLf
RecorrerAList(alDatos)
alDatos.Insert(2, "hola")
TextBox1.Text = TextBox1.Text & "ArrayList después de usar Insert()" & _
vbCrLf
RecorrerAList(alDatos)
alDatos.InsertRange(1, New Integer() {55, 77, 88})
TextBox1.Text = TextBox1.Text & "ArrayList después de usar InsertRange()" & _
vbCrLf
RecorrerAList(alDatos)
alDatos.SetRange(3, New String() {"zzz", "yyy"})
TextBox1.Text = TextBox1.Text & "ArrayList después de usar SetRange()" & _
vbCrLf
RecorrerAList(alDatos)
End Sub

Private Sub RecorrerAList(ByVal alValores As ArrayList)


Dim oEnumerador As IEnumerator = alValores.GetEnumerator()
While oEnumerador.MoveNext()
TextBox1.Text = TextBox1.Text & "Valor: " & oEnumerador.Current & VbCrLf
End While
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Los valores que espera recibir una colección son del tipo genérico Object, por lo que
podemos insertar valores de diferentes tipos de dato.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 375


Recorrer y obtener valores de un ArrayList

Para recorrer un array podemos emplear la técnica habitual del bucle For...Next y la
propiedad Count del objeto ArrayList, que devuelve el número de elementos que tiene
el objeto; o bien podemos usar un objeto del interfaz IEnumerator, proporcionado por
el método GetEnumerator( ), mucho más simple de recorrer. Ver el siguiente código

Private Sub Button1.Click


TextBox1.Text = “ “
' crear ArrayList y añadir valores
Dim alLetras As New ArrayList(6)
alLetras.Add("a")
alLetras.AddRange(New String() {"b", "c", "d"})
' recorrer con un bucle For y usando la propiedad Count,
' tener en cuenta que al ser cero el primer índice del array,
' tenemos que restar uno a la propiedad Count
TextBox1.Text = TextBox1.Text & "Recorrer objeto ArrayList con bucle For" & VbCrLf
Dim iContador As Integer
For iContador = 0 To (alLetras.Count - 1)
TextBox1.Text = TextBox1.Text & "Elemento actual “ & iContador & _
“ valor: “& alLetras(iContador) & vbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf
' recorrer el array con un enumerador
TextBox1.Text =TextBox1.Text & "Recorrer objeto ArrayList con un enumerador" & _
vbCrLf
Dim oEnumerador As IEnumerator
oEnumerador = alLetras.GetEnumerator()
While oEnumerador.MoveNext()
TextBox1.Text = TextBox1.Text & "Elemento de la lista: " & _
oEnumerador.Current() & vbCrLf
End While
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

Capacidad y valores en una colección ArrayList

Cuando manipulamos un objeto ArrayList debemos distinguir entre los conceptos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 376


capacidad y valores asignados.

La capacidad de un ArrayList hace referencia al número de elementos del array


subyacente que contiene este objeto, mientras que los valores asignados se refieren a
aquellos elementos del array a los que se ha asignado valor mediante métodos como Add(
) o AddRange( ). Podemos obtener esta información a través de las propiedades Capacity
y Count del objeto colección. Ver e l código

MsgBox("Valores asignados al array: " & alLetras.Count)


MsgBox("Capacidad del array: "& alLetras.Capacity)

La capacidad es un aspecto de la clase ArrayList que mejora el rendimiento a la hora de


añadir o eliminar elementos del array. Analicemos esta característica con más
detenimiento.

En primer lugar, todo objeto ArrayList dispone de una propiedad oculta llamada _items,
conteniendo el array que internamente gestiona los valores asignados. Esta es una
propiedad que no puede manipular el programador, pero que puede visualizar a través
del depurador, abriendo la ventana Locales y expandiendo el contenido de un objeto
ArrayList. Ver Figura

Cuando creamos un objeto ArrayList con un tamaño como el del último ejemplo, la acción
de añadir un valor a la colección no redimensiona su array subyacente, puesto que ya está
creado con un tamaño determinado, sino que asigna un valor al siguiente elemento libre
que no hubiera sido previamente asignado. Veámoslo en el esquema de la Figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 377


Figura Asignación de valores al array subyacente de una colección ArrayList.

Este comportamiento del objeto tiene la ventaja de que mejora el rendimiento y


optimiza recursos, puesto que cada vez que añadimos o eliminamos valores, el array
_items no siempre tiene que ser redimensionado.

¿Qué sucede, sin embargo, cuando se han añadido valores y el array está completo?, pues
que el objeto ArrayList detecta esta situación y en la siguiente ocasión en que se
añade un nuevo valor, automáticamente redimensiona el array _items, duplicando
el número de elementos inicial que contenía. La Figura muestra un esquema con los
pasos de este proceso.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 378


Figura. Redimensión automática del array _items de un objeto ArrayList.

En el caso que muestra la anterior figura, después de añadir la letra m al objeto, la


propiedad Capacity devolvería 12 y la propiedad Count devolvería 9.

Un detalle muy importante que debe tener en cuenta el lector, es que al crear un objeto
ArrayList, si no especificamos el tamaño, la propiedad _items tiene una capacidad por
defecto de 16 elementos.

Obtención de subarrays a partir de un objeto ArrayList

La clase ArrayList nos proporciona métodos tanto para obtener un fragmento o rango
(subarray) de un objeto ArrayList, como para crear nuevos objetos mediante métodos
shared o compartidos. Entre este tipo de métodos, se encuentran los siguientes.

GetRange(Posición, Elementos). Obtiene un subarray comenzando en el índice


Posición, y tomando el número que indica Elementos.

FixedSize(ArrayList). Método compartido que crea un array de tamaño fijo a


partir de un objeto ArrayList pasado como parámetro. Sobre el nuevo array
obtenido, podemos modificar los elementos existentes, pero no añadir nuevos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 379


Repeat(Valor, Cantidad). Método compartido que crea un ArrayList de valores
repetidos, tomando como valor a repetir el parámetro Valor, y creando tantos
elementos como se especifica en el parámetro Cantidad.

ToArray(). Copia los elementos del ArrayList en un objeto Array, al ser ambos
arrays independientes, el objeto sobre el que se han copiado los elementos puede
modificarse sin que afecte al ArrayList.

ReadOnly( ). Método compartido que crea un objeto ArrayList de sólo lectura a


partir de un array existente.

Veamos algunos ejemplos de uso de estos métodos en el Código fuente:

Private Sub Button4.Click…


TextBox1.Text = “”
Dim alLetras As New ArrayList(10)
alLetras.AddRange(New String() {"a", "b", "c", "d", "e", "f", "g"})
TextBox1.Text = TextBox1.Text & "Array alLetras" & VbCrLf
RecorrerAList(alLetras)
' obtener un subarray con un rango determinado
Dim alRangoLetras As ArrayList
alRangoLetras = alLetras.GetRange(4, 2)
TextBox1.Text = TextBox1.Text &"Array alRangoLetras " & VbCrLf
RecorrerAList(alRangoLetras)
' obtener un subarray de tamaño fijo, se pueden modificar sus elementos,
' no se pueden añadir valores
Dim alLetrasFijo As ArrayList = ArrayList.FixedSize(alLetras)
'alLetrasFijo.Add("m") <-- esto provocaría error
alLetrasFijo(2) = "vvv"
TextBox1.Text = TextBox1.Text & "Array alLetrasFijo " & VbCrLf
RecorrerAList(alLetrasFijo)

' ArrayList de valores repetidos


Dim alRepetidos As ArrayList
alRepetidos = ArrayList.Repeat("hola", 3)
alRepetidos.Add("otro valor")
TextBox1.Text = TextBox1.Text & "Array alRepetidos" & VbCrLf
RecorrerAList(alRepetidos)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 380


' copiar ArrayList sobre un array normal
Dim aNuevo As Array
aNuevo = alLetras.ToArray()
aNuevo(2) = "zzz"
TextBox1.Text = TextBox1.Text & "Array aNuevo" & VbCrLf
RecorrerArray(aNuevo)

' crear ArrayList de sólo lectura a partir de un array existente


Dim alLetrasSoloLeer As ArrayList = ArrayList.ReadOnly(alLetras)
' solamente podemos recorrerlo
TextBox1.Text = TextBox1.Text & "ArrayList de sólo lectura" & VbCrLf
RecorrerAList(alLetrasSoloLeer)

' las dos líneas siguientes provocarían un error


'alLetrasSoloLeer.Add("yyy")
'alLetrasSoloLeer(2) = "wwer"
End Sub

Private Sub RecorrerAList(ByVal alValores As ArrayList)


Dim oEnumerador As IEnumerator = alValores.GetEnumerator()
While oEnumerador.MoveNext()
TextBox1.Text = TextBox1.Text &"Valor: " & oEnumerador.Current & VbCrLf
End While
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Private Sub RecorrerArray(ByVal aValores As Array)


Dim oEnumerador As IEnumerator = aValores.GetEnumerator()
While oEnumerador.MoveNext
TextBox1.Text = TextBox1.Text & "Valor: " & oEnumerador.Current & VbCrLf
End While
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Respecto a los ArrayList de tamaño fijo, tipo FixedSize, queremos advertir al lector que
a la hora de ver su contenido en el depurador, no debe consultar la propiedad _items
mencionada anteriormente, ya que esta contendrá un array de valores vacíos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 381


Este punto puede crear confusión, ya que el lector al ejecutar la aplicación sí obtendrá los
valores de la colección FixedSize, por lo que se preguntará dónde han ido a parar esos
valores.

El secreto reside en el siguiente lugar: al ejecutar con el depurador, debemos expandir la


propiedad [System.Collections.ArrayList.FixedSizeArrayList] del ArrayList con tamaño fijo.
Dentro de esta propiedad, que es realmente una variante del objeto ArrayList, abriremos
la propiedad _list, y de nuevo dentro de esta propiedad encontraremos otra con el nombre
_items, la cual será la que contiene realmente los valores del array de tamaño fijo. La
Figura muestra la ventana Locales del depurador ejecutando el ejemplo.

Figura : Acceso a la lista de valores de un ArrayList de tipo FixedSize.

Búsquedas en colecciones ArrayList

Además de los métodos IndexOf( ) y LastIndexOf( ), disponibles en los arrays estándar,


un ArrayList aporta el método Contains( ), que nos devuelve un valor lógico indicando
si el valor pasado como parámetro existe en el array. Veamos unos ejemplos en el Código
:

Private Sub Button3.Click…


TextBox1.Text = “”
Dim alLetras As New ArrayList(10)
alLetras.AddRange(New String() {"jj", "oo", "aa", "jj", "ee", "tt", "mm", "xx"})
Dim iPosicIndexOf As Integer
' buscar un elemento de la colección desde el principio

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 382


iPosicIndexOf = alLetras.IndexOf("aa")
TextBox1.Text = TextBox1.Text & "Posición al buscar con IndexOf: " & _
iPosicIndexOf & VbCrLf
Dim iPosicLastIndexOf As Integer
' buscar un elemento de la colección desde el final
iPosicLastIndexOf = alLetras.LastIndexOf("jj")
TextBox1.Text = TextBox1.Text & "Posición al buscar con LastIndexOf: " _
& iPosicLastIndexOf & VbCrLf
Dim bEncontrado As Boolean
' comprobar si existe un valor en la colección
bEncontrado = alLetras.Contains("oo")
TextBox1.Text = TextBox1.Text & "Resultado de la búsqueda con Contains: " & _
bEncontrado & VbCrLf
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Borrado de elementos en una colección ArrayList

Para realizar un borrado de valores, la clase ArrayList proporciona los métodos


descritos a continuación.

Remove(Valor). Elimina el elemento del array que corresponde a Valor.

RemoveAt(Posicion). Elimina el elemento del array situado en el índice Posición.

RemoveRange(Posición, Elementos). Elimina el conjunto de elementos


indicados en el parámetro Elementos, comenzando por el índice Posición.

Clear( ). Elimina todos los elementos del objeto.

Debido a las causas de optimización en cuanto a ejecución comentadas en un apartado


anterior, al borrar elementos de un ArrayList, el valor de la propiedad Capacity
permanece inalterable. Eso quiere decir que si añadimos muchos valores a un ArrayList
para después eliminar gran parte de ellos, el array subyacente de la propiedad _items
no disminuirá su tamaño para ahorrar recursos. Esto no es algo preocupante sin
embargo, puesto que si utilizamos el método TrimToSize( ) de esta clase,
conseguiremos que el tamaño o capacidad del ArrayList se ajuste al número real de
elementos que contiene. El Código muestra algunos ejemplos de borrados sobre este tipo

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 383


de objeto.

Private Sub bottono1. Click…


TextBox1.Text = “”
' borra todos los elementos
Dim alLetras1 As New ArrayList(10)
alLetras1.AddRange(New String() {"a", "b", "c", "d", "e", "f", "g"})
alLetras1.Clear()
Estado("alLetras1", alLetras1)

' borra un elemento por el valor


Dim alLetras2 As New ArrayList(10)
alLetras2.AddRange(New String() {"a", "b", "c", "d", "e", "f", "g"})
alLetras2.Remove("c")
Estado("alLetras2", alLetras2)

' borra un elemento por posición


Dim alLetras3 As New ArrayList(10)
alLetras3.AddRange(New String() {"a", "b", "c", "d", "e", "f", "g"})
alLetras3.RemoveAt(5)
Estado("alLetras3", alLetras3)

' borra un rango de elementos por posición


Dim alLetras4 As New ArrayList(10)
alLetras4.AddRange(New String() {"a", "b", "c", "d", "e", "f", "g"})
alLetras4.RemoveRange(2, 3)
TextBox1.Text = TextBox1.Text & "Array alLetras4: estado antes de reajustar
tamaño" & VbCrLf
Estado("alLetras4", alLetras4)

' reajustar capacidad del array


alLetras4.TrimToSize()
TextBox1.Text = TextBox1.Text & "Array alLetras4: estado después de reajustar
tamaño" & VbCrLf
Estado("alLetras4", alLetras4)
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 384


Public Sub Estado(ByVal sNombre As String, ByVal alValores As ArrayList)
TextBox1.Text = TextBox1.Text & "Array: “ & sNombre & VbTab & _
“ Capacidad: “ & alValores.Capacity & VbTab & “ Número de elementos: " &
alValores.Count & VBCrLf
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Ordenar elementos en un objeto ArrayList

Al igual que en la clase base Array, los objetos ArrayList disponen del método Sort( ), que
ordena los elementos del array; y del método Reverse( ), que invierte las posiciones de
un número determinado de elementos del array. El Código muestra un ejemplo de cada
uno.

Private Sub Botton1.Click….


TextBox1.Text = “”
Dim alLetras As New ArrayList(10)
alLetras.AddRange(New String() {"z", "t", "c", "a", "k", "f", "m"})
' ordenar
alLetras.Sort()
TextBox1.Text = TextBox1.Text & "ArrayList después de ordenar" & VbCrLf
RecorrerAList(alLetras)
' invertir posiciones de elementos
alLetras.Reverse(3, 3)
TextBox1.Text = TextBox1.Text & "ArrayList después de invertir elementos" &
VbCrLf
RecorrerAList(alLetras)
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Private Sub RecorrerAList(ByVal alValores As ArrayList)


Dim oEnumerador As IEnumerator = alValores.GetEnumerator()
While oEnumerador.MoveNext()
TextBox1.Text = TextBox1.Text &"Valor: " & oEnumerador.Current & VbCrLf
End While
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub
La clase Hashtable

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 385


Esta clase tiene la particularidad de que el acceso a los valores del array que gestiona
internamente se realiza a través de una clave asociada a cada elemento, al estilo de los
objetos Dictionary de versiones anteriores de VB. Como dato significativo, esta clase
implementa el interfaz IDictionary, por lo que si hemos utilizado anteriormente objetos
Dictionary, ya conocemos gran parte de su filosofía de trabajo.

En este tipo de colección no es necesario preocuparse por la posición o índice de los


elementos, ya que accedemos a ellos a través de literales, lo cual en algunas
circunstancias es mucho más cómodo de manejar.

Manejo básico de colecciones Hashtable


Supongamos como ejemplo, que un proceso en una aplicación necesita guardar de
forma temporal, datos de un cliente en un array. Podemos naturalmente utilizar un
array estándar para tal fin, como muestra el Código:

Dim aCliente = Array.CreateInstance(GetType(Object), 6)


aCliente(0) = 22
aCliente(1) = "Pedro"
aCliente(2) = "Naranjo"
aCliente(3) = "C/Rio Bravo, 25"
aCliente(4) = 35
aCliente(5) = 250

En un planteamiento como el anterior, debemos acordarnos, a la hora de obtener los


datos del array, que la primera posición corresponde al código de cliente, la siguiente al
nombre, etc.,. Bien es cierto que podemos utilizar constantes numéricas para cada
posición, pero sigue siendo una solución poco flexible.

Utilizando un objeto Hashtable sin embargo, tenemos la ventaja de que no


necesitamos saber la posición en que se encuentra cada valor, ya que precisamente a
cada posición le damos un nombre clave que es mediante el que accedemos
posteriormente cuando queremos obtener los valores. El ejemplo siguiente, mejora
sustancialmente el fuente del caso anterior, al estar basado en una colección
Hashtable.

PrivateSub Botton1.Click…
TextBox1.Text = “”

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 386


' declarar colección Hashtable
Dim htCliente As Hashtable
htCliente = New Hashtable()
' añadir valores
htCliente.Add("ID", 22)
htCliente.Add("Nombre", "Pedro")
htCliente.Add("Apellidos", "Naranjo")
htCliente.Add("Domicilio", "C/Rio Bravo, 25")
htCliente.Add("Edad", 35)
htCliente.Add("Credito", 250)

' mostrar el número de elementos que contiene


TextBox1.Text = TextBox1.Text & "El objeto Hashtable tiene “ & _
htCliente.Count & “ elementos" & vbCrLf
TextBox1.Text = TextBox1.Text & VbCrLf
' obtener algunos valores
TextBox1.Text = TextBox1.Text & "Obtener algunos valores del objeto Hashtable" _
& VbCrLf
TextBox1.Text = TextBox1.Text & "Domicilio: "& htCliente.Item("Domicilio") _
& vbCrLf
TextBox1.Text = TextBox1.Text & "Nombre: "& htCliente("Nombre") & vbCrLf
TextBox1.Text = TextBox1.Text & "Credito: " & htCliente("Credito") & vbCrlf
TextBox1.Text = TextBox1.Text & vbCrLf
' recorrer el array al completo
TextBox1.Text = TextBox1.Text &"Recorrer objeto Hashtable con un enumerador" _
&vbCrLf
Dim oEnumerador As IDictionaryEnumerator
oEnumerador = htCliente.GetEnumerator()
While oEnumerador.MoveNext()
TextBox1.Text = TextBox1.Text &"Clave: “ & oEnumerador.Key & vbtab & _
“ Valor: " & oEnumerador.Value & vbCrLF
End While
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

Para crear un nuevo objeto Hashtable hemos utilizado el constructor sin parámetros,
que es el más básico disponible. Puesto que se trata de un constructor sobrecargado,
sugerimos al lector que consulte la documentación de .NET Framework para ver una

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 387


lista completa de todos los constructores disponibles.

Respecto a la asignación de valores a la colección, esta clase utiliza el método Add( ), cuyo
primer parámetro corresponde a la clave del elemento y el segundo corresponde al valor
que vamos a asignar a la posición de su array. Para obtener un valor del array utilizamos el
método Item( ), pasando como parámetro el nombre de la clave de la que vamos a obtener
el valor correspondiente. Al tratarse del método por defecto de esta clase no es necesario
especificarlo. Como hemos podido comprobar, el resultado es el mismo tanto si
especificamos como si no el nombre del método.

Si queremos recorrer el array al completo contenido en el objeto, podemos utilizar


el método GetEnumerator( ), que nos devuelve un enumerador para poder obtener todos
los valores del objeto en un bucle. La diferencia con los otros algoritmos de recorrido que
hemos visto anteriormente, es que al estar la colección Hashtable basada en una
combinación de clave/valor, necesitamos un enumerador basado en el interfaz
IDictionaryEnumerator, especialmente adaptado para manipular arrays de este tipo.

Como habrá comprobado el lector, un enumerador IDictionaryEnumerator proporciona la


información de la colección mediante las propiedades Key y Value, a diferencia de un
enumerador simple, basado en IEnumerator, en el que usamos la propiedad Current, para
extraer los datos.

La clase Hashtable no sitúa los valores que se añaden al array en posiciones consecutivas,
por lo que al obtener los valores mediante un enumerador posiblemente no aparecerán en
el mismo orden en el que los añadimos inicialmente. Dada la filosofía de funcionamiento
de este tipo de objetos, el orden en el que se graban los valores dentro del array no debería
ser un problema, ya que nosotros accedemos al array utilizando claves y no índices, como
sucede en un array estándar.

Operaciones varias con colecciones Hashtable

Antes de obtener valores de un objeto Hashtable, podemos comprobar que la clave o


valor que necesitamos están realmente en la colección, empleando respectivamente los
métodos ContainsKey( ) y ContainsValue( ). Al primero le pasamos como parámetro la clave
a buscar, mientras que al segundo le pasamos el valor. Ambos métodos devuelven un
resultado de tipo Boolean, que indica si la comprobación tuvo o no éxito.

Por otra parte, el método Remove( ), elimina un elemento del objeto, pasándole como

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 388


parámetro la clave a borrar, mientras que el método Clear( ), elimina el contenido
completo de la colección. El Código muestra un ejemplo.

Private Sub Button1.Click….


TextBox1.Text = “”
' crear colección Hashtable y añadir valores
Dim htCliente As New Hashtable()
htCliente.Add("ID", 22)
htCliente.Add("Nombre", "Pedro")
htCliente.Add("Apellidos", "Naranjo")
htCliente.Add("Domicilio", "C/Rio Bravo, 25")
htCliente.Add("Edad", 35)
htCliente.Add("Credito", 250)
' comprobar la existencia de elementos por la clave
Dim sClave As String
sClave = Inputbox("Introducir la clave a buscar")
sClave =Trim(sClave)
If htCliente.ContainsKey(sClave) Then
TextBox1.Text = TextBox1.Text & "La clave “ & sClave & “ existe, su valor es: "
_& htCliente(sClave) & VbCrLf
Else
TextBox1.Text = TextBox1.Text & "La clave “ & sClave & “ NO existe" & VbCrLf
End If
TextBox1.Text = TextBox1.Text & VbCrLf
' comprobar la existencia de elementos por el valor
Dim oValor As Object
oValor = InputBox("Introducir el valor a buscar")
' antes de comprobar si existe el valor debemos hacer una conversión al tipo
' específico de dato del contenido de la variable oValor
If IsNumeric(oValor) Then
oValor = CType(oValor, Integer)
Else
oValor = CType(oValor, String)
End If
' ahora comprobamos
If htCliente.ContainsValue(oValor) Then
TextBox1.Text = TextBox1.Text & "El valor “ & oValor & ” existe" & VbCrLf
Else

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 389


TextBox1.Text = TextBox1.Text & "El valor “ & oValor &” no existe" & VbCrLf
End If
' para borrar un elemento se usa la clave
htCliente.Remove("Nombre")
TextBox1.Text = TextBox1.Text & VbCrLf
RecorrerHT(htCliente)
' ahora borramos el contenido al completo del objeto
htCliente.Clear()
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Public Sub RecorrerHT(ByVal htTabla As Hashtable)


Dim oEnumerador As IDictionaryEnumerator
oEnumerador = htTabla.GetEnumerator()
While oEnumerador.MoveNext()
TextBox1.Text = TextBox1.Text & "Clave: “ & oEnumerador.Key & “ Valor: " & _
oEnumerador.Value & VbCrLf
End While
End Sub

Las propiedades Keys y Values de la clase Hashtable, devuelven un array con los nombres
de las claves y los valores de un objeto Hashtable respectivamente. Realmente devuelven
un objeto del interfaz ICollection, pero ya que un array implementa este interfaz, dicho
objeto podemos manipularlo como un array.

Seguidamente mostramos un ejemplo del uso de estas propiedades en el Código. Observe


el lector el diferente modo de declarar y obtener los objetos ICollection e IEnumerator,
que en definitiva, nos llevan al mismo resultado, demostrando así, la gran flexibilidad
sintáctica que la especificación CLS proporciona al lenguaje.

Private Sub button1.Click….


TextBox1.Text = “”
' crear y llenar la colección
Dim htCliente As New Hashtable()
htCliente.Add("ID", 22)
htCliente.Add("Nombre", "Pedro")
htCliente.Add("Apellidos", "Naranjo")
htCliente.Add("Domicilio", "C/Rio Bravo, 25")

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 390


htCliente.Add("Edad", 35)
htCliente.Add("Credito", 250)
TextBox1.Text = TextBox1.Text & "Coleccion HashTable original " & vbCrLf
RecorrerHT(htCliente) ‘Nota: Este procedimiento esta en programa anterior
TextBox1.Text = TextBox1.Text & vbCrLf
' obtener un array con las claves, y recorrer con un enumerador
Dim aClaves As ICollection
aClaves = htCliente.Keys
Dim oEnumerador As IEnumerator
oEnumerador = aClaves.GetEnumerator()
TextBox1.Text = TextBox1.Text & "Claves del objeto Hashtable" & VbCrLf
RecorrerEnumerador(oEnumerador)

' obtener un array con los valores, y recorrer con un enumerador


Dim aValores As ICollection = htCliente.Values
Dim oEnumVal As IEnumerator = aValores.GetEnumerator()
TextBox1.Text = TextBox1.Text & "Valores del objeto Hashtable" &vbCrLf
RecorrerEnumerador(oEnumVal)
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Public Sub RecorrerEnumerador(ByVal oEnumerador As IEnumerator)


While oEnumerador.MoveNext
TextBox1.Text = TextBox1.Text & oEnumerador.Current & VbCrLf
End While
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Traspaso de elementos desde una colección Hashtable a un array básico

El método CopyTo( ) de la clase Hashtable, se encarga de traspasar a un array


estándar un determinado número de elementos desde un objeto Hashtable. Como ya
sablemos, cada elemento de una colección de este tipo está formado realmente por dos
componentes, clave y valor; por ello, cabe preguntarse cómo se las ingenia esta clase
para poder traspasarlos a un array normal.

La respuesta es la siguiente: lo que realmente se traspasa al array normal no


son valores independientes, sino una estructura de tipo DictionaryEntry, cuyas

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 391


propiedades son precisamente Key y Value, es decir, la clave y valor del elemento de la
colección.

El Código muestra un ejemplo, en el cual, después de crear un objeto Hashtable con


sus correspondientes valores, creamos un array normal de tipo Object al que
traspasamos los elementos desde el Hashtable.

Private Sub Botton2.Click…


'traspaso a un arreglo basico
TextBox1.Text = ""
' crear un array Hashtable
Dim htCliente As New Hashtable()
htCliente.Add("ID", 22)
htCliente.Add("Nombre", "Pedro")
htCliente.Add("Apellidos", "Naranjo")
htCliente.Add("Domicilio", "C/Rio Bravo, 25")
htCliente.Add("Edad", 35)
htCliente.Add("Credito", 250)

' crear un array estándar


Dim aDeposito(10) As Object
aDeposito(0) = "aaa"
aDeposito(1) = "bbb"
aDeposito(2) = "ccc"
aDeposito(3) = "ddd"
Dim iContador As Integer
' impresion del arreglo basico
TextBox1.Text = TextBox1.Text & "datos del arreglo " & vbCrLf
For iContador = 0 To 3
TextBox1.Text = TextBox1.Text & aDeposito(iContador) & vbTab & vbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf

' volcar elementos del Hashtable al array estándar,


' comenzando a copiar desde una posición determinada del array estándar
htCliente.CopyTo(aDeposito, 2)

' obtener algunos valores del objeto Hashtable que se han pasado al array normal
Dim oEntradaDicc As DictionaryEntry

TextBox1.Text = TextBox1.Text & "datos trasladados al arreglo " & vbCrLf


For iContador = 3 To 6
oEntradaDicc = aDeposito(iContador)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 392


TextBox1.Text = TextBox1.Text & "Clave: " & vbTab & oEntradaDicc.Key & vbTab &
" Valor: " & oEntradaDicc.Value & vbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

Como el array normal tenía valores asignados previamente, algunos de ellos se pierden,
puesto que el método CopyTo( ) no redimensiona el array normal. Tenga este hecho en
cuenta el lector, ya que el array destino deberá tener el suficiente tamaño cuando
traspasamos valores desde una colección de este tipo.

La clase SortedList

Esta clase es una variación de Hashtable, ya que nos permite crear colecciones basadas
en pares de claves y valor, pero con la diferencia de que en una colección SortedList, los
elementos se ordenan por la clave según van siendo agregados. El funcionamiento general,
es básicamente igual que para los objetos Hashtable. Veamos un ejemplo en el Código:

Private Sub botton2.click…..


' crear una colección
Dim slListaOrden As New SortedList()
' según añadimos elementos, se van
' ordenando dinámicamente
slListaOrden.Add("H", 111)
slListaOrden.Add("A", 222)
slListaOrden.Add("Z", 333)
slListaOrden.Add("M", 444)
' recorrer la colección SortedList
Dim oEnumerador As IDictionaryEnumerator
oEnumerador = slListaOrden.GetEnumerator()
While oEnumerador.MoveNext()
TextBox1.Text = TextBox1.Text & "Clave: “ &oEnumerador.Key & “ Valor: "
& oEnumerador.Value & VbCrLf
End While
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub
La clase Queue

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 393


Esta clase implementa toda la operativa de una lista de tipo FIFO (first in, first out),
primero en entrar/primero en salir; también denominada cola de valores. A pesar de lo
básico de su funcionalidad, es un aspecto que el programador agradece en muchas
situaciones. La Figura muestra un esquema del funcionamiento de este tipo de objeto.

Figura Representación gráfica del funcionamiento de una colección Queue.

Como el resto de clases en el espacio de nombres System.Collections, los objetos de


tipo Queue contienen un array gestionado por la propia clase e inaccesible para el
programador, que almacena los valores que vamos encolando. Este array parte con un
tamaño inicial y es redimensionado por el propio objeto cuando todos sus elementos
han sido asignados y se intenta añadir un nuevo valor.

Manipulación de valores en una colección Queue

El método Enqueue( ) añade nuevos valores, que quedan situados al final de la lista,
del modo ilustrado en la figura anterior.

Para desarrollar un ejemplo de uso de la clase Queue, vamos a plantear la siguiente


situación: necesitamos implementar un sistema de recepción y envío de mensajes. El primer
mensaje entrante se situará en la lista de modo que será el primero en enviarse, el
segundo mensaje recibido será el siguiente enviado y así sucesivamente.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 394


El Código mostrado a continuación, ilustra el modo de introducción de valores, en un
estilo diferente al utilizado en los anteriores ejemplos. En este caso, en lugar de
introducir directamente por código los valores en la lista, utilizaremos el método
ReadLine( ) del objeto Console, de manera que el usuario introduzca los valores que
precise. Cuando pulse [INTRO] sin haber escrito valor alguno, se considerará que ha
terminado la introducción de datos.

Private Sub button2.Click….


' crear objeto Queue, cola de valores
Dim aqListaMensa As New Queue()
TextBox1.Text = TextBox1.Text & "Introducir mensajes" & VbCrLf
Dim sMensaje As String
' bucle de recepción de mensajes
Do
sMensaje = Input(“Escriba mensaje, no escriba y enter para terminar”)
' si hemos escrito algo...
If sMensaje.Length > 0 Then
' añadimos a la cola
aqListaMensa.Enqueue(sMensaje)
Else
' si no escribimos nada salimos
Exit Do
End If
loop

' la propiedad Count nos indica la cantidad de ' elementos en la lista


TextBox1.Text = TextBox1.Text & "Hay “ aqListaMensa.Count & “ mensajes para
procesar" & vbCrLf

' con un enumerador recorremos la lista


Dim oEnumerador = aqListaMensa.GetEnumerator()
TextBox1.Text = TextBox1.Text & "Contenido del objeto Queue" &VbCrLf
TextBox1.Text = TextBox1.Text & VbCrLf
RecorrerEnumerador(oEnumerador)

TextBox1.Text = TextBox1.Text & VbCrLf


End Sub
Public Sub RecorrerEnumerador(ByVal oEnumerador As IEnumerator)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 395


While oEnumerador.MoveNext
TextBox1.Text = TextBox1.Text & oEnumerador.Current & VbCrLf
End While
TextBox1.Text = TextBox1.Text & VbCrLf
End Sub

Normalmente, en un sistema de gestión de mensajes, una vez que solicitamos un


mensaje, este es enviado y borrado de su contenedor. Pues algo similar es lo que
haremos seguidamente, ya que después de que el usuario haya introducido todos los
mensajes, utilizaremos el método Dequeue( ), que irá extrayendo o desencolando cada
uno de los valores de la lista, comenzando por el primero que fue introducido. Este
método, además de devolver el valor, lo elimina de la lista. Ver el Código fuente

Private Sub Botton1.Click….


' utilizando el método Dequeue() para desencolar
Dim aqListaMensa As New Queue()
Dim sMensaje As String
Dim iContador As Integer

' bucle de recepción de mensajes


Do
iContador += 1
TextBox1.Text = TextBox1.Text & " Mensaje nro. " & iContador & vbCrLf
sMensaje = InputBox("escriba mensaje , no escriba y enter para terminar")
' si hemos escrito algo...
If sMensaje.Length > 0 Then
' añadimos a la lista
aqListaMensa.Enqueue(sMensaje)
Else
' si no escribimos salimos
Exit Do
End If
Loop
TextBox1.Text = TextBox1.Text & vbCrLf

' la propiedad Count nos indica la cantidad de elementos en la lista


TextBox1.Text = TextBox1.Text & "Hay " & aqListaMensa.Count & " mensajes para
procesar" & vbCrLf
TextBox1.Text = TextBox1.Text & vbCrLf
' procesar los mensajes de la lista
iContador = 0
TextBox1.Text = TextBox1.Text & "Procesar lista de mensajes" & vbCrLf

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 396


While aqListaMensa.Count > 0
iContador += 1
TextBox1.Text = TextBox1.Text & "Mensaje nro. " & iContador & vbTab & " texto: "
& vbTab & _
aqListaMensa.Dequeue() & vbCrLf
TextBox1.Text = TextBox1.Text & "Quedan " & aqListaMensa.Count & " mensajes
por procesar" & vbCrLf
TextBox1.Text = TextBox1.Text & vbCrLf
End While
TextBox1.Text = TextBox1.Text & vbCrLf

End Sub

Pero supongamos que queremos comprobar el contenido del próximo mensaje a


procesar antes de sacarlo de la lista. En ese caso, el método Peek( ) de la clase
Queue es el indicado, ya que precisamente devuelve el siguiente valor de la lista sin
eliminarlo, como ilustra el Código :

TextBox1.Text = TextBox1.Text & "Obtenemos el primer valor sin eliminar: " &
aqListaMensa.Peek())

Puede ocurrir también, que necesitemos obtener los valores de la lista pero sin
eliminarlos, por ejemplo, para poder repetir el proceso posteriormente. ¿Tenemos que
volver a pedirlos al usuario?, no en absoluto, ya que mediante el método Clone( ) de la clase
Queue, podemos obtener un nuevo objeto independiente, pero con los mismo elementos.
A partir de ese momento, aunque procesemos la lista original, mantendremos los datos en
una copia del objeto.

Otra técnica consiste en utilizar el método ToArray( ), que copia los valores de la lista a
un array estándar. Dicho array deberá haber sido previamente creado con el tamaño
adecuado, ya que si tiene menos elementos que el objeto Queue, cuando copiemos los
valores al array se producirá un error.

Para saber el tamaño del array que tenemos que crear, podemos ayudarnos de la propiedad
Count del objeto Queue. El Código muestra unos ejemplos.

Private Sub Form1.Load …


' crear objeto Queue e introducir valores
Dim aqListaMensa As New Queue()
'....

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 397


' crear copia de seguridad de la lista
Dim aqCopiaMensajes As Queue = aqListaMensa.Clone()
' o también, podemos crear un array normal con los elementos del objeto Queue
Dim aListaDatos As Array = Array.CreateInstance(GetType(Object), _
aqListaMensa.Count)
aListaDatos = aqListaMensa.ToArray()
' procesar los mensajes de la lista original, mantendremos los valores en el objeto
' clonado o en un array
TextBox1.Text = TextBox1.Text & " datos de la cola " & vbCrLf
Dim oEnumerador = aqListaMensa.GetEnumerator()
RecorrerEnumerador(oEnumerador)
TextBox1.Text = TextBox1.Text & vbCrLf

End Sub

Copiando los valores a un array, tenemos la ventaja de poder ordenarlos, o hacer cualquier
operación que nos permita la clase Array. Y ya para terminar con esta clase, el método
Clear() elimina todos los valores del array interno que mantiene un objeto Queue. Podemos
utilizar este método en el caso de que después de haber obtenido algunos valores de la lista,
no queramos seguir extrayendo información, pero necesitemos el objeto vacío para poder
repetir el proceso de captura de datos.

La clase Stack

Al igual que en el caso anterior, esta clase nos permite gestionar colas de valores, pero
los objetos de este tipo, crean listas de valores al estilo de pilas LIFO (last in, first out),
último en entrar/primero en salir.

Su modo de manejo es similar a las colecciones Queue, con la característica de que en


una pila, los valores que extraemos son los últimos que han entrado. Veamos un ejemplo en
el Código :

Private Sub Button1.click…


' creamos una colección de tipo pila
Dim oPila As Stack
oPila = New Stack()
' para añadir valores, usamos el método Push()
oPila.Push("A") ' este será el último en salir
oPila.Push("B")
oPila.Push("C")
oPila.Push("D")

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 398


oPila.Push("E") ' este será el primero en salir
' para extraer un valor de la pila, usamos el método Pop(),
'dicho valor se eliminará de la lista
TextBox1.Text = TextBox1.Text & " Obtenemos los datos de la pila creada " & vbCrLf
TextBox1.Text = TextBox1.Text & vbCrLf
While oPila.Count > 0
TextBox1.Text = TextBox1.Text & "El valor obtenido de la pila es: " & oPila.Pop &
vbCrLf
End While
End Sub

Colecciones personalizadas

Cuando el tipo de array que necesitamos no existe

Los arrays básicos proporcionados por el entorno de .NET, a través de la clase Array,
proveen al programador, a través del conjunto de miembros que implementan, de
un excelente conjunto de funcionalidades para realizar la manipulación de listas de
valores.

Por si ello no fuera suficiente, disponemos además del espacio de nombres


System.Collection, que aportan un conjunto de clases, que nos facilitan objetos para
manejar arrays con características avanzadas.

Pese a todo, habrá ocasiones en que necesitemos trabajar con un array de un modo
especial, y no dispongamos entre los miembros de la clase Array, ni entre las
clases de Collection, de las funcionalidades requeridas. Sin embargo, gracias a la
arquitectura orientada a objeto de la plataforma, podemos crear nuestras propias clases
para la manipulación de arrays, heredando de las colecciones existentes o
implementando los interfaces necesarios.

Utilizando la herencia para crear una nueva colección

Situémonos en primer lugar en un escenario de ejemplo: estamos desarrollando una


aplicación en la que utilizamos colecciones de tipo ArrayList. Sin embargo,
necesitamos que dichas colecciones admitan sólo números, y que además, el array de
la colección esté ordenado.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 399


Dado que estas características no están implementadas en los objetos ArrayList, pero
este tipo de colección se adapta en gran medida a nuestras necesidades, crearemos una
nueva clase con el nombre NumerosOrden, que herede de ArrayList, y en la que
codificaremos el comportamiento personalizado que necesitamos. Ver el Código:

' Creamos una clase que herede de ArrayList, que ordene los elementos del array,
' y que sólo admita números
Class NumerosOrden
Inherits ArrayList
' sobrescribimos el método Add() de la clase base;
' sólo vamos a permitir añadir números a la colección
Public Overrides Function Add(ByVal value As Object) As Integer
' si es un número, añadimos
If IsNumeric(value) Then
MyBase.Add(value) ' llamamos al método base
Me.Sort() ' ordenamos el array
Return Me.Count ' devolvermos el número de elementos que hay
Else
' si no es un número...
Return -1
End If
End Function
End Class

Para usar esta clase desde el código cliente, instanciaremos un objeto y trabajaremos con
él como si se tratara de una colección normal. Ver el Código siguiente:

Private Sub Form1.Load…


' instanciar un objeto de nuestra
' colección personalizada que ordena números
Dim oNumOr As New NumerosOrden()
oNumOr.Add(980)
oNumOr.Add(500)
oNumOr.Add(25)
oNumOr.Add(700)
' recorrer la colección
Dim oEnumera As IEnumerator = oNumOr.GetEnumerator()
TextBox1.Text = TextBox1.Text & "Colección ordenada de números" & vbcCrLf

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 400


While oEnumera.MoveNext
TextBox1.Text = TextBox1.Text & "valor: "& oEnumera.Current & vbCrLf
End While
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

En este ejemplo, el lector ha podido comprobar cómo con una mínima cantidad de código
en una clase derivada, conseguimos toda la potencia de una colección base, y
le proporcionamos un comportamiento del que originalmente carecía.

Implementando un interfaz para crear una nueva colección

Como acabamos de comprobar en el ejemplo anterior, la creación de nuevas clases de


tipo collection mediante herencia es una estupenda solución. Debido a que el código
principal ya existe en la clase base, simplemente tenemos que añadir el código para el
nuevo comportamiento en la clase derivada, mediante la creación de nuevos miembros,
a través de sobrecarga, o sobre-escritura. Sin embargo, esta técnica tiene el
inconveniente de que no podemos modificar o eliminar ciertos comportamientos de la
clase base.

Para salvar este obstáculo, en lugar de heredar de una colección, podemos emplear otra
técnica, que consiste en crear una clase, e implementar en ella uno o varios interfaces de
los incluidos en el espacio de nombres System.Collections, los cuales definen las
características que deben tener los arrays y colecciones del entorno.

La ventaja de implementar interfaces de colección en una clase, reside en que


tenemos control absoluto en cuanto al comportamiento que tendrán los objetos
collection que instanciemos de dicha clase. Aunque como inconveniente, tenemos el
hecho de que la implementación de un interfaz, obliga a codificar todos los miembros
que vienen en la declaración de dicho interfaz; respecto a esto último, podemos escribir
sólo la declaración de algunos miembros y no su código; de esta manera, para
aquellos aspectos del interfaz en los que no estemos interesados, no será necesario
codificar.

Supongamos como ejemplo, que necesitamos en nuestro programa una colección


que convierta a mayúsculas los valores que añadimos o modificamos. Para ello, vamos a
crear una clase con el nombre ListaMay, que implemente el interfaz IList. Este interfaz
está compuesto por un numeroso conjunto de miembros, pero nosotros sólo vamos a

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 401


codificar los siguientes.

Add( ). Añadir un nuevo elemento.

Item( ). Asigna u obtiene un valor.

Contains( ). Comprueba si existe un valor entre los elementos de la colección,


devolviendo un valor lógico Verdadero si existe, o Falso en el caso de que no exista.

Count. Devuelve el número de elementos que hay en la colección.

GetEnumerator( ). Devuelve un enumerador para recorrer el array de la colección.

Clear( ). Elimina los valores de los elementos del array que tiene la colección.

Para el resto de miembros del interfaz, aunque no vayamos a utilizarlos, debemos crear
su declaración vacía, ya que en caso contrario, se producirá un error al intentar
ejecutar el programa, porque el entorno detectará la falta de la creación de los
miembros de dicho interfaz en nuestra clase.

No codificamos todos los miembros del interfaz para simplificar el presente ejemplo,
y al mismo tiempo, demostramos que sólo hemos de escribir código para aquellos
aspectos del interfaz que necesitemos, aunque lo recomendable sería, evidentemente,
implementar correctamente todos los métodos y propiedades que indica el interfaz.
Veámoslo en el Código:

' esta clase implementa la funcionalidad de una colección;


' admite como elementos cadenas de caracteres, y los convierte a mayúsculas
Class ListaMay
' para conseguir el comportamiento de una colección
' en esta clase implementamos el siguiente interfaz Implements IList
' declaramos un array que contendrá los valores de la colección
Protected aValores() As String
' a partir de aquí, debemos declarar todos los miembros
' del interfaz, y codificar aquellos que necesitemos
' -----------------------------------------------------
Public ReadOnly Property Count() As Integer _
Implements System.Collections.IList.Count

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 402


Get
If Not (aValores Is Nothing) Then
Count = aValores.Length
End If
End Get
End Property
Public ReadOnly Property IsSynchronized() As Boolean _
Implements System.Collections.IList.IsSynchronized
Get
End Get
End Property
Public ReadOnly Property SyncRoot() As Object _
Implements System.Collections.IList.SyncRoot
Get
End Get
End Property
Public Function GetEnumerator() As System.Collections.IEnumerator _
Implements System.Collections.IList.GetEnumerator
Return aValores.GetEnumerator()
End Function

Public Function Add(ByVal value As Object) As Integer _


Implements System.Collections.IList.Add
If aValores Is Nothing Then
ReDim Preserve aValores(0)
aValores(0) = CStr(value).ToUpper()
Else
Dim iIndiceMayor As Integer = aValores.GetUpperBound(0)
ReDim Preserve aValores(iIndiceMayor + 1)
aValores(iIndiceMayor + 1) = CStr(value).ToUpper()
End If
Return Me.Count
End Function

Public Sub Clear() _


Implements System.Collections.IList.Clear
Array.Clear(aValores, 0, aValores.Length)
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 403


Public Function Contains(ByVal value As Object) As Boolean _
Implements System.Collections.IList.Contains
Dim oEnumera As IEnumerator
oEnumera = aValores.GetEnumerator()
While oEnumera.MoveNext
If (oEnumera.Current = CType(value, String).ToUpper()) Then
Return True
End If
End While
Return False
End Function
Public Function IndexOf(ByVal value As Object) As Integer _
Implements System.Collections.IList.IndexOf
End Function
Public ReadOnly Property IsFixedSize() As Boolean _
Implements System.Collections.IList.IsFixedSize
Get
End Get
End Property

Public ReadOnly Property IsReadOnly() As Boolean _


Implements System.Collections.IList.IsReadOnly
Get
End Get
End Property

Default Public Property Item(ByVal index As Integer) As Object _


Implements System.Collections.IList.Item
Get
Item = aValores.GetValue(index)
End Get
Set(ByVal Value As Object)
Dim oTipo As Type
oTipo = Value.GetType()
If oTipo.Name = "String" Then
aValores.SetValue(CType(Value, String).ToUpper(), index)
Else

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 404


aValores.SetValue(Value, index)
End If
End Set
End Property

Public Sub Remove(ByVal value As Object) _


Implements System.Collections.IList.Remove
End Sub
Public Sub RemoveAt(ByVal index As Integer) _
Implements System.Collections.IList.RemoveAt
End Sub
Public Sub Insert(ByVal index As Integer, ByVal value As Object) _
Implements System.Collections.IList.Insert
End Sub
Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer) _
Implements System.Collections.IList.CopyTo
End Sub
End Class

Desde código cliente, el modo de utilizar nuestra nueva clase es igual que para una de
las colecciones normales, aunque debemos tener en cuenta los métodos no codificados,
para no utilizarlos. Veamos el Código :

Private Sub Botton1.Click


' instanciar un objeto de la colección personalizada
Dim oLis As ListaMay = New ListaMay()
TextBox1.Text = TextBox1.Text &"Número de elementos " & oLis.Count & vbCrLf
TextBox1.Text = TextBox1.Text & vbCrLf
' añadir valores
oLis.Add("Esta es")
oLis.Add("mi clase")
oLis.Add("de arrays personalizados")
RecorrerMiLista(oLis)
TextBox1.Text = TextBox1.Text &"Número de elementos " & oLis.Count & vbCrLf
TextBox1.Text = TextBox1.Text & vbCrLf
' comprobar si existe un valor
Dim sValorBuscar As String
TextBox1.Text = TextBox1.Text &"Introducir un valor a buscar en la colección" &

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 405


vbCrLf
sValorBuscar = Console.ReadLine()
If oLis.Contains(sValorBuscar) Then
TextBox1.Text = TextBox1.Text &"El valor introducido sí existe" & vbCrLf
Else
TextBox1.Text = TextBox1.Text &"El valor introducido no existe" & vbCrLf
End If
TextBox1.Text = TextBox1.Text & vbCrLf
' eliminar valores de la colección (no elimina elementos)
oLis.Clear()
' asignar valores a los índices existentes de la colección
oLis(2) = "mesa"
oLis.Item(0) = "coche"
RecorrerMiLista(oLis)
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

Public Sub RecorrerMiLista(ByVal oListaValores As ListaMay)


Dim oEnumera As IEnumerator
oEnumera = oListaValores.GetEnumerator()
While oEnumera.MoveNext
TextBox1.Text = TextBox1.Text & "valor " & oEnumera.Current & vbCrLf
End While
TextBox1.Text = TextBox1.Text & vbCrLf
End Sub

11.- GDI+ Sistema gráfico de Windows


GDI+ es la evolución de GDI, el API para la manipulación de gráficos incluido en anteriores
versiones de Windows.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 406


Al tratarse de un interfaz de programación independiente del dispositivo físico sobre el
que se van a generar los gráficos, el programador gana en flexibilidad, ya que no debe
preocuparse de si el gráfico generado se va a mostrar por el monitor, impresora, etc.;
esta labor es resuelta por GDI+, que aísla el programa del hardware a manejar.

GDI+ divide su campo de trabajo en tres áreas principales.

Generación de gráficos vectoriales 2D


Manipulación de imágenes en los formatos gráficos más habituales.
Visualización de texto en un amplio abanico de tipos de letra.

En versiones anteriores del lenguaje, el objeto Form disponía de una serie de métodos y
controles para el dibujo sobre la superficie del formulario. La mayor parte de esos
elementos han desaparecido en la actual versión de VB, integrándose todas las operaciones
de dibujo en las clases de .NET Framework; con ello, lo que aprendamos sobre trabajo
con gráficos en VB.NET utilizando GDI+, nos servirá igualmente si en un futuro debemos
abordar un proyecto en otro lenguaje de la plataforma, ya que las clases pertenecen a .NET
Framework y no a un lenguaje en particular.

Otro problema con el que nos enfrentábamos anteriormente era el hecho de que al
necesitar alguna manipulación gráfica especial, teníamos que recurrir al API de Windows.
A partir de ahora esto no será necesario, ya que como hemos comentado, es el propio
entorno de ejecución de .NET el que nos proporciona dicho acceso, por lo que no será
necesario acudir al API del sistema operativo.

System.Drawing

Para utilizar las clases relacionadas con la manipulación de gráficos, es preciso importar
este espacio de nombres.

System.Drawing contiene el conjunto de clases principales, aunque no es el único


namespace de GDI+; para tareas de mayor especialización con gráficos deberemos
recurrir a alguno de los siguientes espacios de nombre que están dentro de
System.Drawing: Drawing2D, Imaging y Text.

Dibujo con las clases Graphics y Pen

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 407


La clase Graphics representa el denominado Contexto de dispositivo gráfico (Graphics device
context)
sobre el que se va a realizar una operación de dibujo, por ejemplo, el formulario.

Debido a la arquitectura del sistema gráfico, no es posible tomar un objeto Form y


realizar una operación directa de dibujo sobre el mismo, sino que precisamos en
primer lugar, obtener una referencia hacia el área de dibujo de dicho formulario, o
contexto gráfico, y una vez obtenida esa referencia, efectuar el dibujo.

Este área lo vamos a obtener mediante el método CreateGraphics( ) de la clase Form, que
devuelve un objeto Graphics con la información del contexto de dispositivo gráfico del
formulario, que usaremos para dibujar sobre el mismo, mediante el conjunto de métodos
DrawXXX( ).

Por otro lado, la clase Pen representa un objeto de tipo lapicero o bolígrafo, que con un
determinado color y grosor, utilizará un objeto Graphics para dibujar líneas y formas en un
contexto de dispositivo,
es decir, el formulario.

El Código fuente 535 muestra un ejemplo de dibujo de un círculo sobre el formulario


utilizando el método DrawEllipse( ) de Graphics. Este método recibe como parámetro un
objeto Pen con un color y grosor determinados y un objeto Rectangle con las
coordenadas y medida necesarias para dibujar el círculo.

' crear objeto Pen


Dim oPen As New Pen(Color.DeepPink, 10)

' obtener el contexto de dispositivo


' gráfico del formulario
Dim oGraphics As Graphics = Me.CreateGraphics()

' dibujar en el formulario


oGraphics.DrawEllipse(oPen, New Rectangle(150, 20, 100, 100))

Asociando este código a la pulsación de un botón en el formulario, el resultado será el


dibujo del círculo mostrado en la Figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 408


. Dibujar un círculo con un objeto Pen.

Sin embargo, el dibujo de figuras de esta manera tiene un inconveniente, puesto que si el
formulario es ocultado parcial o totalmente por otro, la zona ocultada se dice que ha
quedado invalidada, y requiere un repintado, labor que actualmente, no indicamos que se
haga en el código del formulario.

Para mantener las figuras dibujadas en el formulario en todo momento, debemos


recurrir al evento Paint( ) de la clase Form. Dicho evento se produce cada vez que el
formulario necesita repintarse porque parte o la totalidad de su superficie ha quedado
invalidada

Vamos por lo tanto a observar las diferencias codificando el mencionado evento Paint( ),
en el que dibujaremos un rectángulo. Ver Código fuente

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As


System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
' crear objeto Pen
Dim oPen As New Pen(Color.MediumVioletRed, 6)
' obtener el contexto de dispositivo
' gráfico del formulario; en este caso usaremos el objeto que contiene
' los argumentos de evento para obtener dicho contexto de dispositivo
Dim oGraph As Graphics = e.Graphics
' dibujar en el formulario
oGraph.DrawRectangle(oPen, New Rectangle(40, 80, 70, 70))

End Sub

Al ejecutar el programa, el rectángulo será mostrado en todo momento, aunque

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 409


minimicemos el formulario, lo ocultemos parcial, totalmente, etc., ya que este evento se
ejecuta automáticamente cada vez que el formulario detecta que su superficie ha
quedado invalidada y necesita repintarse. La Figura muestra el formulario con ambas
figuras dibujadas, si ocultamos y mostramos de nuevo la ventana, comprobaremos
como el círculo ha desaparecido mientras que el rectángulo persiste.

Figuras dibujadas en la superficie del formulario desde un botón y el evento Paint.

El proyecto GraficosGDI , contiene a través de las opciones de sus menús, el conjunto de


operaciones de dibujo que describiremos seguidamente.

Mediante el menú Dibujo con Pen, dibujaremos un círculo, rectángulo, curva, polígono, etc.
Consulte el lector sus opciones para comprobar el código para cada tipo de figura.
A continuación comentaremos las más destacables.

Al dibujar un rectángulo vamos a modificar el estilo de línea mediante la propiedad


DashStyle. Esta propiedad contiene una enumeración con la que podemos hacer que la
línea se muestre como guiones, guiones y puntos, etc. Ver Código fuente

Private Sub mnuPenRectangulo_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuPenRectangulo.Click

' crear objeto Pen


Dim oPen As New Pen(Color.Firebrick, 4)

' aplicar un estilo de línea con la propiedad

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 410


' DashStyle --> guión, punto
oPen.DashStyle = Drawing.Drawing2D.DashStyle.DashDot

' obtener el contexto de dispositivo


' gráfico del formulario
Dim oGraphics As Graphics = Me.CreateGraphics()

' dibujar en el formulario


oGraphics.DrawRectangle(oPen, New Rectangle(280, 75, 120, 40))

End Sub

Si queremos aplicar más estilos a la línea del objeto Pen, disponemos también de las
propiedades StartCap, EndCap, DashCap. El Código fuente 538 muestra el dibujo de una
curva con varios efectos de línea. Al dibujar una curva, necesitamos pasar al método
DrawCurve( ) un array de tipos Point, con las coordenadas de referencia a usar para el dibujo
de la curva.

Private Sub mnuPenCurva_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuPenCurva.Click

' crear objeto Pen


Dim oPen As New Pen(Color.MediumPurple, 5)

' configurar estilo de línea


oPen.DashStyle = Drawing.Drawing2D.DashStyle.DashDot
oPen.StartCap = Drawing.Drawing2D.LineCap.Triangle
oPen.EndCap = Drawing.Drawing2D.LineCap.DiamondAnchor
oPen.DashCap = Drawing.Drawing2D.DashCap.Triangle

' obtener el contexto de dispositivo gráfico del formulario


Dim oGraphics As Graphics = Me.CreateGraphics()

' crear un array de puntos-coordenadas necesario para dibujar una curva


Dim oPuntos(4) As Point
oPuntos(0) = New Point(10, 200)
oPuntos(1) = New Point(40, 100)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 411


oPuntos(2) = New Point(100, 20)
oPuntos(3) = New Point(130, 100)
oPuntos(4) = New Point(200, 200)

' dibujar en el formulario


oGraphics.DrawCurve(oPen, oPuntos)

End Sub

En cuanto a las curvas de tipo Bezier, el método DrawBezier( ) recibe como parámetros, el
objeto Pen y una lista de coordenadas para el dibujo. Ver el Código fuente

Private Sub mnuPenBezier_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuPenBezier.Click
' dibujar curva estilo Bezier
Dim oGraphics As Graphics = Me.CreateGraphics()
oGraphics.DrawBezier(New Pen(Color.MediumSeaGreen, 2), 20, 45, 100, 90, 140,
200, 300, 25)
End Sub

La Figura muestra todas las formas dibujadas con objetos Pen.

Si en un momento dado, necesitamos borrar los elementos gráficos dibujados en la


superficie del formulario, utilizaremos el método Invalidate( ) de la clase Form, que en este
ejemplo está disponible en la opción de menú Abrir + Borrar. Ver Código fuente .

Private Sub mnuBorrar_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuBorrar.Click
' borrar las figuras dibujadas en el formulario
Me.Invalidate()

End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 412


. Figuras dibujadas con objetos de la clase Pen.

La clase Brush
Esta clase representa un objeto de tipo brocha, utilizado para rellenar de diferentes formas,
las figuras dibujadas sobre el formulario.

Se trata de una clase abstracta, por lo que tendremos que utilizar alguna de sus
diversas clases derivadas, según el estilo de brocha que necesitemos aplicar. Debido
a las características 2D de algunas de estas clases, tendremos que importar en nuestro
código el espacio de nombres Drawing2D.

Los métodos de la clase Graphics que utilizaremos para dibujar con brochas serán los que
comienzan por el nombre FillXXX( )

El menú Dibujo con Brush del formulario de este ejemplo, muestra algunas de las
operaciones de dibujo y estilos de relleno, que podemos aplicar con las clases de tipo Brush.

La clase más básica es SolidBrush, que permite rellenar en un estilo sencillo un área
dibujada. Ver el Código fuente

Private Sub mnuBrushSolid_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuBrushSolid.Click

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 413


Dim oBrush As New SolidBrush(Color.MidnightBlue)
Dim oGraphics As Graphics = Me.CreateGraphics()
oGraphics.FillRectangle(oBrush, New Rectangle(150, 160, 150, 50))

End Sub

A continuación tenemos la clase HatchBrush, que permite la creación de brochas que al


pintar aplican un efecto de tramado con un color de fondo y frente. Ver el Código fuente

Private Sub mnuBrushHatch_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuBrushHatch.Click

' pintar con brocha de tipo hatch; para utilizar este tipo de brocha
' necesitamos importar System.Drawing.Drawind2D

' crear objeto HatchBrush


Dim oHatchBrush As New HatchBrush(HatchStyle.Vertical, Color.Fuchsia,
Color.Aqua)

' dibujar y pintar un polígono


Dim oGraphics As Graphics = Me.CreateGraphics()
oGraphics.FillEllipse(oHatchBrush, New Rectangle(25, 40, 150, 50))

End Sub

Podemos emplear un bitmap como base para la zona de relleno que tendrá que
pintarse, para ello usaremos la clase TextureBrush, pasándole como parámetro un
objeto Bitmap, que previamente habremos creado, y que contendrá un fichero con la
textura necesaria. Ver Código fuente

Private Sub mnuBrushTextura_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuBrushTextura.Click

' crear un bitmap


Dim oBitmap As New Bitmap("textura1.bmp")

' crear una brocha de textura


Dim oTextureBrush As New TextureBrush(oBitmap)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 414


' dibujar una figura y pintarla con la brocha de textura
Dim oGraphics As Graphics = Me.CreateGraphics()
oGraphics.FillEllipse(oTextureBrush, New Rectangle(220, 15, 100, 75))

End Sub

Para efectos avanzados de relleno, consistentes en degradados de colores,


utilizaremos las clases LinearGradientBrush y PathGradientBrush. Una vez creado
un objeto Brush de estas clases, aplicaremos un conjunto de colores que serán
mezclados para crear un efecto de degradado o fundido en el área a pintar, mediante
el constructor y/o las propiedades de la clase que corresponda. Ver Código fuente

' pintar figura con brocha LinearGradientBrush


Private Sub mnuBrushLinearG_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuBrushLinearG.Click
' crear brocha de tipo LinearGrad.
Dim oLGB As New LinearGradientBrush(New Rectangle(10, 50, 40, 60),
Color.Aquamarine, Color.Azure, LinearGradientMode.Horizontal)
' crear array de coordenadas
Dim oPuntos(2) As Point
oPuntos(0) = New Point(20, 200)
oPuntos(1) = New Point(75, 100)
oPuntos(2) = New Point(140, 220)
' obtener contexto gráfico
Dim oGraphics As Graphics = Me.CreateGraphics()
' dibujar y pintar una curva cerrada
oGraphics.FillClosedCurve(oLGB, oPuntos)
End Sub
'-------------------------------------------
' pintar figura con brocha PathGradientBrush
Private Sub mnuBrushPathG_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuBrushPathG.Click

' array de coordenadas


Dim oPuntos(2) As Point
oPuntos(0) = New Point(100, 150)
oPuntos(1) = New Point(175, 80)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 415


oPuntos(2) = New Point(210, 150)

' crear brocha de tipo PathGradient,


' y configurar el objeto
Dim oPGB As New PathGradientBrush(oPuntos)
oPGB.CenterColor = Color.Indigo
oPGB.SurroundColors = New Color() {Color.Beige, Color.LightGreen}

' crear gráfico y pintar polígono


Dim oGraphics As Graphics = Me.CreateGraphics()
oGraphics.FillPolygon(oPGB, oPuntos)

End Sub

La Figura muestra todas las formas dibujadas con objetos de los tipos derivados de Brush.

Figuras dibujadas y pintadas con objetos derivados de Brush.

Dibujo de texto en el formulario

Aparte de los controles que nos permiten visualizar y editar texto en un formulario,
como Label, TextBox, etc., podemos realizar operaciones de dibujo de texto en la

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 416


superficie del formulario, empleando el método DrawString( ) de la clase Graphics.

El texto visualizado mediante esta técnica no es evidentemente editable, se


encamina fundamentalmente a mostrar texto con efectos adicionales que no podríamos
conseguir mediante los controles típicos.

En el formulario de nuestro ejemplo, la opción de menú Texto + Dibujar texto, crea


un objeto HatchBrush con un tramado específico, un objeto Font de una determinada
familia, y con ambos elementos, pinta el texto mediante un objeto Graphics. Ver el
Código fuente

Private Sub mnuTextoTxt_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles mnuTextoTxt.Click
' crear un objeto Brush con efectos
Dim oBrush As New HatchBrush(HatchStyle.Wave, Color.Aqua, Color.DarkGreen)
' crear el tipo de letra
Dim oFont As New Font(New FontFamily("Georgia"), 50)
' obtener el dispositivo gráfico del formulario y pintar el texto
Dim oGraf As Graphics = Me.CreateGraphics()
oGraf.DrawString("Texto en modo gráfico", _
oFont, oBrush, New RectangleF(20, 20, 500, 200))
End Sub

La Figura muestra el texto dibujado en el formulario.

Dibujo de texto empleando clases de manipulación de gráficos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 417


Personalización de la imagen de fondo del formulario

En un tema anterior explicamos que la propiedad BackgroundImage nos permite asignar


un fichero de imagen para el fondo del formulario. La facilidad que proporciona
esta propiedad tiene desafortunadamente su lado negativo, ya que el tamaño de
la imagen asignada, no se adapta automáticamente al del formulario.

Por tal motivo, en este apartado vamos a proporcionar al lector un par de técnicas, que
le permitirán crear imágenes de fondo para formularios con ajuste dinámico, para
que la imagen adapte sus dimensiones a las del formulario, cuando este cambie su
tamaño en tiempo de ejecución.

Manipulación de los eventos de pintado en la clase Form

El primer ejemplo, contenido en el proyecto FondoFormManual se basa en la codificación


del evento Paint( ) de la clase Form.

Dentro del procedimiento manipulador de este evento, creamos un objeto Bitmap


que contenga la referencia hacia un fichero con el gráfico a mostrar de fondo, y con un
objeto Graphics, obtenido del parámetro EventArgs del evento, pintamos el objeto
Bitmap. Ver el Código fuente 546.

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As


System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
' crear un objeto bitmap
Dim oBitmap As New Bitmap("LogoWin.gif")
' pintar el objeto con el contexto gráfico del formulario;
' el area a pintar abarca desde la coordenada 0,0 y toma el ancho
' y alto del formulario de su propiedad Size
Dim oGraphics As Graphics = e.Graphics
oGraphics.DrawImage(oBitmap, 0, 0, Me.Size.Width, Me.Size.Height)
End Sub

Queda todavía un paso más, ya que aunque la imagen se muestra como fondo del
formulario, si redimensionamos este, sólo se repinta la parte nueva redimensionada,
produciendo un efecto no deseado. Ver Figura

Para conseguir que se pinte por completo toda la imagen, debemos invalidar la zona

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 418


gráfica del formulario mediante su método Invalidate( ), en el evento Resize, el cual es
provocado cada vez que cambia el formulario de tamaño. Después de escribir el
Código fuente cuando volvamos a ejecutar el ejemplo, la imagen de fondo se adaptará
en todo momento a las medidas del formulario.

Imagen de fondo con repintado irregular.

Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs)


Handles MyBase.Resize
' cada vez que cambie el tamaño del formulario invalidamos su área 'de dibujo para
que el evento Paint pinte toda la superficie
Me.Invalidate()
End Sub

Empleo del control PictureBox

Después de la técnica compleja (sólo en parte), vamos ahora con el modo fácil para crear
una imagen de fondo, que pasa por el uso del control PictureBox.

Este control nos permite la visualización de imágenes en el formulario de un modo


sencillo, ya que toda la mecánica de generación la lleva incorporada, con lo que el
programador se despreocupa de la manipulación del gráfico a mostrar.

El proyecto FondoFormPicB contiene esta aplicación para que el lector pueda realizar las

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 419


pruebas que requiera.

Una vez insertado un PictureBox en el formulario, asignaremos a su propiedad Dock el


valor Fill; de esta forma el control ocupará por completo la superficie del formulario.

A continuación asignaremos el fichero con la imagen a la propiedad Image, y por último,


tenemos que establecer la propiedad SizeMode al valor StretchImage. Esto será todo,
por lo que si ejecutamos el programa, la imagen quedará en todo momento ajustada al
formulario al igual que en el anterior caso. Ver Figura

. Imagen de fondo del formulario empleando un PictureBox.

Manipulando el grado de opacidad del formulario

La propiedad Opacity de la clase Form, contiene un valor numérico de tipo Double


que permite establecer el grado de opacidad del formulario. Cuando esta propiedad
contenga el valor 1, el formulario se mostrará en la forma habitual; pero si el valor es
0, el formulario será transparente.

Podemos asignar valores intermedios de modo que hagamos parcialmente transparente


el formulario, mostrando los elementos que quedan bajo el mismo. Debemos tener en
cuenta que cuando asignemos este valor mediante la ventana de propiedades del
formulario en modo de diseño, el número asignado será el porcentaje de opacidad. La
Figura muestra la ventana de propiedades para este caso con un setenta y cinco por ciento
de opacidad para el formulario.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 420


Propiedad Opacity establecida desde la ventana de propiedades del IDE.

La Figura muestra este formulario con el anterior porcentaje de opacidad.

Formulario parcialmente transparente debido a la propiedad Opacity.

El Código fuente establece por código la opacidad del formulario a un grado del cuarenta
y cinco por ciento, en el evento DoubleClick del formulario.

Private Sub Form1_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs)


Handles MyBase.DoubleClick
Me.Opacity = 4.5
End Sub

El proyecto Opacidad contiene un control TrackBar, que con el estilo de un control de


volumen, nos va a permitir graduar el nivel de opacidad del formulario.

Mediante las propiedades Maximum y Minimum establecemos el rango de opacidad


respectivamente a diez y cero.
En la propiedad Value asignaremos el valor 10, para partir de la máxima opacidad e ir
disminuyendo. Como efectos visuales de este control, las propiedades Orientation y
TickStyle nos permiten establecer la orientación del indicador de posición y su apariencia.

Finalmente, el evento Scroll se producirá cada vez que movamos el indicador de

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 421


posición en el control, ejecutando el código de su procedimiento manipulador, que vemos
en el Código fuente

Private Sub tkbOpaco_Scroll(ByVal sender As Object, ByVal e As System.EventArgs)


Handles tkbOpaco.Scroll
' cada vez que se mueve el desplazador del TrackBar se modifica la opacidad

Select Case Me.tkbOpaco.Value


Case 0
Me.Opacity = 0
Case 10
Me.Opacity = 1
Case Else
Me.Opacity = "0," & Me.tkbOpaco.Value
End Select

End Sub

La Figura muestra este ejemplo en ejecución.

Esta útil característica de los formularios nos permite, por ejemplo, proporcionar un
efecto de fundido durante su proceso de cierre. Para conseguirlo, escribiremos el
manipulador para el evento Closing del formulario, que es producido cuando el formulario
está a punto de cerrarse; en dicho procedimiento de evento, cancelaremos en ese
momento el cierre del formulario, crearemos un temporizador que conectaremos
con un manipulador del evento Tick, y lo pondremos en marcha.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 422


Utilizando un TrackBar para graduar la opacidad de un formulario.

En el procedimiento del evento Tick, crearemos el efecto de fundido, disminuyendo


el grado de opacidad del formulario hasta hacerlo invisible, punto en el que cerraremos
el formulario. Esto hará que se vuelva a pasar por el evento Closing, pero en esta
ocasión, como la opacidad del formulario estará a cero, no se volverá a realizar el
proceso de fundido. Todo esto lo vemos en el Código fuente

Private Sub Form1_Closing(ByVal sender As Object, ByVal e As


System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
Dim oTiempo As Timer

' el formulario debe tener el valor 1 en Opacity para conseguir el efecto


If Me.Opacity <> 0 Then
' cancelamos el cierre del formulario
e.Cancel = True
' iniciamos un temporizador cada medio segundo
oTiempo = New Timer()
oTiempo.Interval = 500
' conectamos el temporizador con un manipulador de su evento Tick
AddHandler oTiempo.Tick, AddressOf TickTiempo
oTiempo.Start()
End If
End Sub

Private Sub TickTiempo(ByVal sender As Object, ByVal e As EventArgs)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 423


' este manipulador del evento del temporizador, cada medio segundo irá
' disminuyendo el grado de opacidad del formulario hasta hacerlo invisible
Static dbContador As Double = 1
dbContador -= 0.1
Me.Opacity = dbContador
' cuando el formulario es invisible
If Me.Opacity = 0 Then
' parar el temporizador
CType(sender, Timer).Stop()
' cerrar el formulario
Me.Close()
End If
End Sub

Modificación de la forma del formulario

Las capacidades gráficas del GDI+ nos permiten dotar a los formularios de efectos hasta la
fecha muy difíciles de conseguir, si no se conocía en profundidad el API de Windows.

Aspectos como la transparencia del formulario tratada en el apartado anterior, o el cambio


en la forma estándar del formulario, que veremos seguidamente.

Para cambiar el aspecto rectangular de un formulario debemos, en primer lugar, importar


en nuestro programa, el espacio de nombres System.Drawing.Drawing2D.

A continuación crearemos un objeto de la clase GraphicsPath, que representa un conjunto


de líneas y curvas conectadas. A este objeto le añadiremos una forma mediante alguno de
sus métodos AddXXX( ).

Finalmente, crearemos un objeto de tipo Region, al que pasaremos el objeto


GraphicsPath con la forma creada previamente. Esto creará una región con dicha forma,
que asignaremos a la propiedad Region del formulario, consiguiendo de esta manera,
modificar el aspecto del formulario en cuanto a su forma.

El proyecto FormasForm muestra un formulario con dos botones que cambian la forma del
formulario a un círculo y triángulo al ser pulsados. El Código fuente muestra los eventos
Click de ambos botones.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 424


Imports System.Drawing.Drawing2D
'....
'....
Private Sub Circulo_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Circulo.Click
' crear un objeto gráfico para conectar líneas y curvas
Dim oGPath As GraphicsPath = New GraphicsPath()
' añadir un círculo al objeto gráfico
oGPath.AddEllipse(New Rectangle(0, 0, 200, 260))
' crear una región con el objeto gráfico y asignarla a la región del formulario
Me.Region = New Region(oGPath)
End Sub

Private Sub btnPoligono_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles btnPoligono.Click
' mostrar el formulario con el aspecto de un triángulo
Dim oPuntos(2) As Point
oPuntos(0) = New Point(-20, -20)
oPuntos(1) = New Point(-20, 200)
oPuntos(2) = New Point(220, 90)
Dim oGPath As GraphicsPath = New GraphicsPath()
oGPath.AddPolygon(oPuntos)
Me.Region = New Region(oGPath)
End Sub

La Figura muestra el formulario con forma de elipse.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 425


Formulario con forma de elipse.

La Figura muestra el formulario con forma de triángulo.

Formulario con forma triangular.

Integrando elementos. Un visualizador de gráficos


Para finalizar con el presente tema, vamos a realizar, a modo de práctica, una aplicación que
contendrá un formulario para visualizar archivos de imagen. De esta forma practicaremos
con algunos de los puntos ya tratados, y nos servirá para presentar dos nuevos controles:
TreeView y ListView.

para acceder a este ejemplo), y consiste en crear un formulario con un ComboBox que

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 426


permita, en primer lugar, seleccionar una unidad lógica del equipo. Una vez hecho esto,
se llenará el TreeView con la lista de directorios de la unidad elegida. Al seleccionar un
directorio del TreeView, se rellenará el ListView con una lista de ficheros de tipo gráfico,
de los que al seleccionar uno, se cargará su contenido en un PictureBox; al realizar dicha
carga, podremos optar por ajustar la imagen a las dimensiones del PictureBox o bien
mantener el tamaño original de la imagen. Debido a que algunos de estos controles
necesitan de imágenes asociadas como iconos, utilizaremos también un control
ImageList para almacenar estos iconos.

El control TreeView muestra una lista de elementos dispuestos en forma de árbol o nodos
expandibles.

La propiedad Nodes es una colección que contiene los nodos del control, que en
este caso rellenaremos desde el código del programa. Las propiedades ImageIndex y
SelectedImageIndex muestran respectivamente una de las imágenes del control ImageList
asociado, con el icono indicativo de si un nodo se encuentra o no seleccionado.

Por otro lado, el control ListView consiste en un ListBox al que podemos asociar una
imagen para cada elemento o item que muestra en la lista.

Para poder mostrar los elementos de un ListView de esta forma estableceremos la


propiedad View al valor Details; crearemos una columna en su propiedad Columns, y
asociaremos el control ImageList a las propiedades Large/Small/StateImageList. También
es conveniente que la propiedad MultiSelect esté a False para poder seleccionar sólo
un elemento en cada ocasión. El llenado de este control también lo haremos desde el
código de la aplicación. La Figura muestra el formulario de este proyecto una vez
completada su fase de diseño.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 427


Formulario del visualizador de gráficos.

Pasando al código de la clase del formulario, debido a que vamos a trabajar con objetos
que manipulan directorio y ficheros, importaremos en la cabecera del fichero de
código el espacio de nombres System.IO. En el evento Load del formulario, cargaremos
el ComboBox con las unidades lógicas detectadas por el sistema, empleando el
objeto Environment del sistema, y su método GetLogicalDrives( ). Ver Código
fuente

Imports System.IO
Public Class Form1
Inherits System.Windows.Forms.Form

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs)


Handles MyBase.Load
' al cargar el formulario llenar
' el combo con las letras de unidad
Dim sUnidades() As String
sUnidades = System.Environment.GetLogicalDrives()
Me.cboUnidades.Items.AddRange(sUnidades)
End Sub
'....

Al seleccionar un elemento en el ComboBox, se produce su evento


SelectedIndexChanged, en el que nos ocupamos de obtener los directorios raíz de
la unidad lógica seleccionada, y con dicha información, rellenar el TreeView. Ver
Código fuente 553.

Private Sub cboUnidades_SelectedIndexChanged(ByVal sender As Object, ByVal e As


System.EventArgs) Handles cboUnidades.SelectedIndexChanged
' este evento se dispara cuando se cambia
' el elemento seleccionado del combo
' obtener los directorios raíz de la unidad seleccionada
Dim oDirUnidadSelec As New DirectoryInfo(Me.cboUnidades.Text)
Dim sDirectorios() As DirectoryInfo
sDirectorios = oDirUnidadSelec.GetDirectories()

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 428


' vaciar el treeview
Me.tvDirectorios.Nodes.Clear()
' dibujar cada nombre de directorio raíz en el treeview
Dim oDirInfo As DirectoryInfo
Dim oNodo As TreeNode
For Each oDirInfo In sDirectorios
oNodo = New TreeNode(oDirInfo.FullName, 0, 1)
Me.tvDirectorios.Nodes.Add(oNodo)
Next
End Sub

El siguiente paso lógico es la selección de un directorio en el TreeView. Cuando esto


suceda, se provocará el evento AfterSelect de dicho control; en él comprobaremos si existen
directorios anidados al seleccionado, y al mismo tiempo, llenaremos el ListView con los
nombres de ficheros del directorio seleccionado, asociando a cada elemento de la lista, una
imagen del control ImageList por el número de orden que ocupa la imagen en la lista. Ver
Código fuente

Private Sub tvDirectorios_AfterSelect(ByVal sender As Object, ByVal e As


System.Windows.Forms.TreeViewEventArgs) Handles tvDirectorios.AfterSelect
' si el nodo pulsado no está expandido...
If Not e.Node.IsExpanded Then
' comprobar si tiene subdirectorios
Dim oSubDirInfo As DirectoryInfo
oSubDirInfo = New DirectoryInfo(e.Node.FullPath)

' obtener subdirectorios del directorio seleccionado


Dim oSubDirectorios() As DirectoryInfo
oSubDirectorios = oSubDirInfo.GetDirectories()

' crear nodos para cada subdirectorio en el treeview


Dim oSubDirI As DirectoryInfo
Dim oNodo As TreeNode
For Each oSubDirI In oSubDirectorios
oNodo = New TreeNode(oSubDirI.Name, 0, 1)
e.Node.Nodes.Add(oNodo.Text)
Next

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 429


' obtener los archivos del subdirectorio
Dim oArchivos() As FileInfo
oArchivos = oSubDirInfo.GetFiles()

' limpiar el listview


Me.lstFicheros.Items.Clear()

' rellenar el listview con los nombres de archivo


' que tengan tipo gráfico
Dim oArchInfo As FileInfo
For Each oArchInfo In oArchivos
Select Case oArchInfo.Extension.ToUpper()
Case ".BMP", ".PNG", ".WMF"
Me.lstFicheros.Items.Add(oArchInfo.Name, 3)

Case ".JPG", ".JPEG"


Me.lstFicheros.Items.Add(oArchInfo.Name, 4)

Case ".GIF"
Me.lstFicheros.Items.Add(oArchInfo.Name, 5)
End Select
Next
End If
End Sub

Finalmente, ya sólo queda comprobar cuándo se pulsa en uno de los ficheros de imagen
del ListView, cosa que haremos con su evento SelectedIndexChanged. Al producirse esta
situación, lo que haremos será invalidar el área de dibujo del PictureBox, forzando a
que se desencadene su evento Paint, en donde realmente realizaremos la carga de la
imagen. A pesar de todo, en el Código fuente también se acompaña el código para
hacer una carga directa de la imagen en el evento sobre el que nos encontramos.

Private Sub lstFicheros_SelectedIndexChanged(ByVal sender As Object, ByVal e As


System.EventArgs) Handles lstFicheros.SelectedIndexChanged

If Me.lstFicheros.SelectedItems.Count > 0 Then


' CARGA MANUAL EN PICTUREBOX:
' si invalidamos la región gráfica del picturebox

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 430


' obligamos a que se produzca su evento Paint,
' y en ese evento escribimos el código que carga
' la imagen en el control
Me.picImagen.Invalidate()
' CARGA AUTOMÁTICA DE IMAGEN:
' escribimos en este evento el código para
' asignar una imagen al picturebox
'Me.picImagen.Image = New Bitmap( _
' Me.tvDirectorios.SelectedNode.FullPath & "\" & _
' Me.lstFicheros.SelectedItems(0).Text)
End If
End Sub

En el evento Paint del PictureBox, mostramos la imagen seleccionada, ajustada al tamaño


del control o con su propio tamaño, según el RadioButton seleccionado del formulario.
Adicionalmente, para el caso en el que se redimensione el formulario, también
invalidamos el PictureBox, de manera que la imagen que actualmente se esté mostrando
será recargada. Veámoslo en el Código fuente

Private Sub picImagen_Paint(ByVal sender As Object, ByVal e As


System.Windows.Forms.PaintEventArgs) Handles picImagen.Paint
' si el nodo seleccionado tiene contenido
If Not (IsNothing(Me.tvDirectorios.SelectedNode)) Then
' crear imagen a partir del fichero seleccionado
Dim oBitmap As New Bitmap( _
Me.tvDirectorios.SelectedNode.FullPath & _
"\" & Me.lstFicheros.SelectedItems(0).Text)

' obtener dispositivo gráfico del picturebox


Dim oGraf As Graphics = e.Graphics
If Me.rbtAjustar.Checked Then
' dibujar imagen ajustada al picturebox
oGraf.DrawImage(oBitmap, 0, 0, _
Me.picImagen.Size.Width, Me.picImagen.Size.Height)
Else
' dibujar imagen con su tamaño original
oGraf.DrawImage(oBitmap, 0, 0, _
oBitmap.Size.Width, oBitmap.Size.Height)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 431


End If
End If
End Sub

Private Sub picImagen_Resize(ByVal sender As Object, ByVal e As System.EventArgs)


Handles picImagen.Resize
' al redimensionar, invalidar área gráfica del picturebox
Me.picImagen.Invalidate()
End Sub
Terminada la escritura de código del programa, sólo queda ejecutarlo para comprobar su
resultado, como muestra la Figura

Visualizador de gráficos en ejecución.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 432


12.- Operaciones de entrada y salida (I/O).Gestión del
sistema de archivos

La remodelación del viejo esquema de entrada y salida

Desde las primeras versiones del lenguaje, el programador de Visual Basic ha


dispuesto de un conjunto de instrucciones y funciones para el manejo de las
operaciones de lectura/escritura con archivos, y la gestión de los mismos dentro del
sistema operativo, en cuanto a su creación, borrado copia, etc., entre directorios y
unidades.

Si bien este modo de trabajo ha sido válido durante mucho tiempo, la incorporación de
las técnicas
OOP a los lenguajes de programación, hacían necesario una renovación en este aspecto
de VB.

Las instrucciones Open, Input, Write, Put, etc., a pesar de resolver su cometido, no
proporcionan un entorno de trabajo cómodo, en un mundo en el que cada vez prima más
el trabajo con objetos.

La jerarquía de objetos FileSystemObject, introducida recientemente, vino a paliar


en parte esta carencia, aportando un conjunto de clases que ya nos permitían, desde
un prisma orienta a objeto, trabajar con todos los aspectos del sistema de archivos, en
cuanto a su lectura, escritura, manejo de directorios, unidades, etc. La evolución de este
conjunto de objetos se halla en la plataforma .NET.

System.IO, el punto de partida

Con la llegada de la tecnología .NET, el acceso al sistema de archivos, es un aspecto que


ya no forma parte de un lenguaje determinado, como ocurría en las anteriores versiones
de VB, sino que ha sido integrado dentro de la jerarquía de clases de la plataforma, en
el espacio de nombres IO de System.

Con ello, todos los lenguajes compatibles con .NET podrán utilizar este conjunto de
objetos.

Las clases incluidas en System.IO, nos van a permitir realizar labores de lectura y escritura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 433


en archivos de texto, binarios, etc., así como la creación y manipulación de los
archivos y directorios que contienen la información.

A lo largo de este tema realizaremos una descripción, y ejemplos de uso, de algunas


de las clases contenidas en IO. Por lo que, en todos los ejemplos utilizados aquí,
tendremos que importar este espacio de nombres.

Objetos Stream

Un objeto Stream representa un flujo o corriente de datos, es decir, un conjunto de


información guardada en formato de texto o binario, que podremos leer y escribir sobre
un soporte físico, también denominado en la plataforma .NET, almacén de respaldo
(backing store).

Algunos tipos de Stream, para optimizar el flujo de transferencia de datos entre el objeto
y su medio físico de almacenamiento, disponen de una característica denominada
almacenamiento intermedio (buffering), que consiste en mantener un búfer intermedio
con los datos. En el caso, por ejemplo, de tareas de escritura, todas las operaciones
se realizarían en el búfer, mientras este dispusiera de capacidad. Una vez terminado
el proceso de escritura, o cuando el búfer estuviera lleno, su contenido pasaría al archivo
físico. Podemos también, alterar el comportamiento por defecto del búfer a través de
diversas propiedades y métodos del objeto Stream correspondiente.

Las clases TextReader y TextWriter

Estas clases contienen los miembros genéricos para realizar lectura y escritura de
caracteres.

Se trata de clases abstractas, por lo que deberemos utilizar las clases derivadas
StreamReader, StreamWriter, StringReader y StringWriter, comentadas a continuación.

La clase StreamWriter

Un objeto StreamWriter realiza operaciones de escritura de texto sobre un archivo.

El proceso típico de escritura de datos mediante un StreamWriter, comprende los


siguientes pasos:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 434


Instanciar un objeto de esta clase mediante alguno de los constructores
disponibles. Aquí creamos un nuevo archivo para escribir datos sobre él, o abrimos
uno existente.

Escritura de texto mediante los métodos WriteLine( ) y Write( ). El primero


escribe el texto pasado como parámetro, y añade los caracteres especiales de
retorno de carro y nueva línea. El segundo escribe el texto pasado y deja el
puntero de escritura a partir del último carácter escrito, con lo que no produce
un cambio automático de línea. Deberemos utilizar la propiedad NewLine para
introducir manualmente un salto de línea.

Cierre del Stream con el método Close( ). Esta acción vuelca el contenido del
búfer del objeto en el archivo.

El Código fuente muestra el proceso básico que acabamos de describir.

Imports System.IO

Module Module1
Sub Main()
Dim swEscritor As StreamWriter
' creamos un stream de escritura, y al mismo tiempo un
' nuevo archivo para escribir texto sobre él
swEscritor = New StreamWriter("\pruebas\NOTAS.txt")
' escribir líneas
swEscritor.WriteLine("esta es la primera línea")
swEscritor.WriteLine("segunda línea de texto")
' ahora escribimos texto pero sin provocar un salto de línea
swEscritor.Write("Juan y Luna ")
swEscritor.Write("van de paseo")
swEscritor.Write(swEscritor.NewLine) ' esto introduce el salto de línea

swEscritor.WriteLine("con esta línea cerramos")


' cerrar el stream y el archivo asociado
swEscritor.Close()
End Sub
End Module

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 435


Algunas de las clases de tipo Stream de escritura disponen del campo compartido Null,
que permite realizar una operación de escritura que no será volcada en el medio físico
de almacenamiento, con lo que se perderán los datos escritos. Ver el Código fuente.

' escribir a un medio inexistente (nulo)


swEscritor.Null.WriteLine("este texto no llegará al archivo")

En el caso de que el archivo sobre el que vamos a escribir ya exista, podemos utilizar
un constructor de StreamWriter que nos permite especificar si vamos a añadir texto al
archivo o vamos a sobrescribir, perdiendo el texto que hubiera. Veamos un ejemplo en el
Código fuente

' abre el archivo y se sitúa al final del texto para añadir


swEscritor = New StreamWriter("\pruebas\NOTAS.txt", True)

' se elimina el contenido previo del archivo


swEscritor = New StreamWriter("\pruebas\NOTAS.txt", False)

Después de crear un objeto de este tipo, y escribir algunas líneas de texto sin cerrar
el Stream, si abrimos su archivo de texto correspondiente, nos encontraremos con
que no hay texto dentro del archivo. Ello es debido a que todavía no se ha volcado
el contenido del búfer del objeto sobre el archivo. Para forzar dicho volcado, deberemos
llamar al método Flush( ), que se encarga de traspasar el búfer al archivo asociado al
Stream. Veamos el Código fuente

Dim swEscritor As StreamWriter


' creamos un stream de escritura
swEscritor = New StreamWriter("\pruebas\NOTAS.txt", False)
' escribir líneas
swEscritor.WriteLine("la primera línea")
swEscritor.WriteLine("un poco más de texto")

' si abrimos el archivo antes de la siguiente, estará vacío


swEscritor.Flush()
' ahora el archivo ya contendrá texto
' cerrar el stream y el archivo asociado
swEscritor.Close()

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 436


La clase StreamReader

Un objeto StreamReader realiza operaciones de lectura de texto sobre un archivo.

El proceso que debemos llevar a cabo para leer el contenido de un Stream de lectura es
muy similar al de escritura: instanciar el objeto con uno de sus constructores, abriendo
un archivo para leer; ejecutar alguno de los métodos de lectura del StreamReader, y cerrar
el objeto con Close( ).

Entre los métodos de lectura de este objeto, tenemos ReadLine( ), que devuelve una línea
del archivo; y ReadToEnd( ), que devuelve el resto del contenido del archivo, desde
el punto en el que se encontrara el Stream al realizar la última lectura. Veamos unos
ejemplos en el Código fuente

Dim srLector As StreamReader = New StreamReader("\pruebas\NOTAS.txt")

Console.WriteLine("**Leer una primera línea**")


Dim Linea As String
Linea = srLector.ReadLine()
Console.WriteLine("La línea contiene --> {0}", Linea)

Console.WriteLine()
Console.WriteLine("**Ahora leemos el resto del archivo**")
Dim Texto As String
Texto = srLector.ReadToEnd()
Console.WriteLine("El texto restante contiene --> {0}", Texto)
srLector.Close()

' ***********************************************
' leer línea a línea mediante un bucle
Dim srLector As StreamReader = New StreamReader("\pruebas\Datos.txt")
Dim Linea As String
Dim ContadorLin As Integer = 1
Linea = srLector.ReadLine()
Do While Not (Linea Is Nothing)
Console.WriteLine("Línea: {0} - Contenido: {1}", ContadorLin, Linea)
ContadorLin += 1

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 437


Linea = srLector.ReadLine()
Loop

Otro de los métodos de lectura es ReadBlock( ), que recibe como parámetro un array
de tipo Char, sobre el que se depositarán una cierta cantidad de caracteres leídos
del archivo. En el segundo parámetro de este método indicamos la posición del array
desde la que se comenzarán a guardar los caracteres. En el tercer parámetro, el
número de caracteres a leer.

El método Read( ), también permite realizar una lectura igual que ReadBlock( ), pero en
el caso de no utilizar parámetros, devuelve un valor numérico, correspondiente al código
del carácter que acaba de leer. Cuando llega al final del Stream, devuelve –1.

Para convertir de nuevo a carácter los valores que devuelve Read( ), debemos pasar estos
valores a un array de tipo Byte, y después, utilizando un objeto ASCIIEncoding, mediante
su método GetString( ), pasaríamos el array a una cadena. Veamos unos ejemplos de estos
métodos en el Código fuente

Imports System.IO
Imports System.Text

Module Module1
Sub Main()
' crear un Stream de lectura
Dim srLector As StreamReader = New StreamReader("\pruebas\NOTAS.txt")

' obtener valores del Stream con el método ReadBlock()


' ----------------------------------------------------
' crear un array Char que contendrá los caracteres leídos
Dim Caracteres(15) As Char
' leemos 16 caracteres del archivo y los pasamos al array
' comenzando a grabarlos a partir de su posición 0
srLector.ReadBlock(Caracteres, 0, 16)
' pasamos el array de valores Char a String mediante
' el constructor de la clase String que recibe como
' parámetro un array Char
Dim Parte1 As String = New String(Caracteres)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 438


Console.WriteLine("Resultado de la lectura con ReadBlock()")
Console.WriteLine(Parte1)
Console.WriteLine()

' obtener valores del stream con el método Read()


' -----------------------------------------------
Dim Valor As Integer
Dim Codigos() As Byte
' vamos a ir volcando en un bucle los códigos de carácter
' leidos desde el archivo a un array Byte
Valor = srLector.Read()
While (Valor <> -1) ' cuando lleguemos al final, obtendremos -1
If Codigos Is Nothing Then
ReDim Codigos(0)
Else
ReDim Preserve Codigos(Codigos.GetUpperBound(0) + 1)
End If

Codigos(Codigos.GetUpperBound(0)) = Valor
Valor = srLector.Read()
End While
Dim Codificador As New ASCIIEncoding()
Dim Parte2 As String
' con el objeto ASCIIEncoding, método GetString(),
' obtenemos una cadena, pasando como parámetro un array
' de tipos Byte

Parte2 = Codificador.GetString(Codigos)
Console.WriteLine("Resultado de la lectura con ReadBlock()")
Console.WriteLine(Parte2)
Console.ReadLine()
End Sub
End Module

Finalmente, el método Peek( ), al igual que Read( ), devuelve el siguiente valor disponible
del Stream, pero sin extraerlo del búfer, con lo que deberemos utilizar alguno de los
métodos anteriormente descritos para realizar una lectura real.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 439


Las clases StringWriter y StringReader

Estas clases proporcionan la misma funcionalidad que StreamWriter y StreamReader, con


la diferencia de que StringWriter trabaja con un objeto StringBuilder como almacén
de datos, mientras que StringReader utiliza un String para leer su contenido.

La clase Stream (flujo de datos)

La clase Stream representa un flujo o corriente de datos, es decir, un conjunto


secuencial de bytes, como puede ser un archivo, un dispositivo de entrada/salida,
memoria, un conector TCP/IP, etc.

Se trata de una clase abstracta, por lo que si queremos hacer uso de un stream
concreto, tenemos que acudir a alguna de sus clases derivadas como son FileStream,
MemoryStream, BufferedStream, etc.

La clase FileStream

Realiza escritura y lectura de bytes sobre un archivo; en el caso de que el archivo


no exista, lo crearíamos al mismo tiempo que instanciamos este objeto.

Uno de los constructores de esta clase, nos permite especificar una cadena con la ruta
del archivo a utilizar, mientras que en el segundo parámetro utilizaremos un valor de
la enumeración FileMode, mediante la que indicamos el modo de trabajo sobre el archivo:
añadir, abrir, crear, etc.

Las propiedades CanRead, CanWrite y CanSeek, devuelven un valor lógico que nos
informa de si en el objeto podemos realizar operaciones de lectura, escritura y
desplazamiento por los bytes que contiene.

Para escribir datos, disponemos del método WriteByte( ), que escribe un byte en el
archivo; y también tenemos el método Write( ), que escribe de un array de bytes pasado
como parámetro, una cantidad de elementos determinada empezando por una de las
posiciones de dicho array. Veamos un ejemplo de escritura en el Código fuente 416.

' escrituras con Filestream


Dim oFileStream As FileStream
oFileStream = New FileStream("\pruebas\apuntes.dtt", FileMode.CreateNew)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 440


oFileStream.Write(New Byte() {15, 160, 88, 40, 67, 24, 37, 50, 21}, 0, 6)
oFileStream.WriteByte(75)
Console.WriteLine("Opciones en el FileStream")
Console.WriteLine("Podemos leer: {0}", IIf(oFileStream.CanRead, "SI", "NO"))
Console.WriteLine("Podemos escribir: {0}", IIf(oFileStream.CanWrite, "SI", "NO"))
Console.WriteLine("Podemos movernos: {0}", IIf(oFileStream.CanSeek, "SI", "NO"))
oFileStream.Close()
oFileStream = Nothing

Para las operaciones de lectura, tenemos ReadByte( ), que devuelve el valor sobre
el que esté posicionado el objeto en ese momento. También disponemos del método
Read( ), que traspasa valores un array de bytes.

Si queremos desplazarnos por los elementos del Stream, podemos utilizar el método
Seek( ), pasando la cantidad de posiciones a movernos, y el punto desde el que
queremos realizar dicho desplazamiento, mediante los valores de la enumeración
SeekOrigin.

Para averiguar el elemento del Stream en el que estamos situados, disponemos de


la propiedad Position. Veamos algunos ejemplos de lectura sobre este tipo de objetos,
en el Código fuente

' lectura con FileStream


Dim oFileStream As FileStream
oFileStream = New FileStream("\pruebas\apuntes.dtt", FileMode.Open)
Dim Valor As Byte
Valor = oFileStream.ReadByte() ' obtener un valor
Console.WriteLine("Se ha leido el valor: {0}", Valor)

Console.WriteLine("Nos desplazamos dos bytes en el stream")


oFileStream.Seek(2, SeekOrigin.Begin)

Valor = oFileStream.ReadByte()
Console.WriteLine("Se ha leido el valor: {0}", Valor)
Console.WriteLine("La posición actual del stream es: {0}", _
oFileStream.Position)
' leer varios valores, pasándolos a un array previamente dimensionado
Dim VariosValores(3) As Byte

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 441


oFileStream.Read(VariosValores, 0, 4)

Console.WriteLine("Leer bloque de valores del stream")


Dim Enumerador As IEnumerator
Enumerador = VariosValores.GetEnumerator()
While Enumerador.MoveNext
Console.WriteLine("Valor: {0}", Enumerador.Current)
End While

Las clases BufferedStream y MemoryStream, que también heredan de Stream, disponen


de los mismos miembros que FileStream, teniendo como principal diferencia el que
utilizan la memoria de la máquina como almacén de respaldo.

Manejo de datos binarios

Las clases BinaryWriter y BinaryReader, tal y como podemos anticipar por sus nombres,
nos permiten escribir y leer respectivamente, datos binarios en archivos, utilizando los
métodos ya vistos en clases anteriores. Veamos un ejemplo en el Código fuente

' escritura binaria


Dim oBin As New BinaryWriter(New FileStream("\pruebas\info.bin",
FileMode.CreateNew))
oBin.Write("H"c)
oBin.Write("D"c)
oBin.Write("U"c)
oBin.Close()
oBin = Nothing

' lectura binaria


Dim oBinLector As BinaryReader
oBinLector = New BinaryReader(New FileStream("\pruebas\info.bin", FileMode.Open))

Console.WriteLine("Valor 1 del lector: {0}", oBinLector.ReadChar())


Console.WriteLine("Valor 2 del lector: {0}", oBinLector.ReadChar())
Console.WriteLine("Valor 3 del lector: {0}", oBinLector.ReadChar())
oBinLector.Close()

Console.ReadLine()
Manipulación de archivos mediante File y FileInfo

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 442


Las clases File y FileInfo, proporcionan a través de sus miembros, el conjunto de
operaciones comunes que podemos realizar con archivos en cuanto a su creación, copia,
borrado, etc.

La diferencia principal entre ambas radica en que los miembros de File son todos
compartidos, con lo cual se facilita en gran medida su uso, al no tener que crear una
instancia previa de la clase; mientras que en FileInfo deberemos crear un objeto para
poder utilizarla, ya que sus miembros son de instancia. FileInfo dispone de algunos
métodos adicionales que no se encuentran en File.

Comenzando por la clase File, los métodos CreateText( ) y OpenText( ), devuelven


respectivamente un objeto StreamWriter y StreamReader, que utilizaremos para
escribir y leer en el archivo pasado como parámetro a estos métodos. Con el método
Exists( ), comprobamos si existe un determinado
archivo. Veamos un ejemplo en el Código fuente

Dim sNombreFich As String


Dim srLector As StreamReader
Dim swEscritor As StreamWriter
Console.WriteLine("Introducir ruta y archivo")
sNombreFich = Console.ReadLine()
If File.Exists(sNombreFich) Then
srLector = File.OpenText(sNombreFich)
Console.WriteLine("El archivo contiene:{0}{1}", _
ControlChars.CrLf, srLector.ReadToEnd())
srLector.Close()
Else

swEscritor = File.CreateText(sNombreFich)
swEscritor.WriteLine("este es")
swEscritor.WriteLine("un nuevo archivo")
swEscritor.Close()

End If

MsgBox("Proceso finalizado")

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 443


Console.ReadLine()

Para obtener los atributos de un archivo, disponemos del método GetAttributes( ), al


que pasamos la ruta de un archivo, y devuelve un valor de la enumeración FileAttributes
con la información sobre los atributos. En el caso de que al intentar acceder a un archivo,
este no exista, se producirá una excepción de tipo FileNotFoundException, que podemos
tratar en una estructura de manejo de excepciones. Ver el Código

Dim sNombreFich As String


Dim oAtributos As FileAttributes
Try
Console.WriteLine("Introducir ruta y archivo")
sNombreFich = Console.ReadLine()
oAtributos = File.GetAttributes(sNombreFich)
Console.WriteLine("Atributos del archivo: {0}", oAtributos.ToString())

Catch oExcep As FileNotFoundException


Console.WriteLine("Se ha producido un error {0}{1}", _
ControlChars.CrLf, oExcep.Message)
Finally
Console.WriteLine("Proceso finalizado")
Console.ReadLine()
End Try

Además de esta excepción, el espacio de nombres IO proporciona algunas clases de


excepción adicionales para tratar otras diversas circunstancias de error. Consulte el lector
la documentación de la plataforma referente a IO.

Los métodos Copy( ), Move( ) y Delete( ), nos permiten copiar, mover y borrar
respectivamente el nombre de archivo que pasemos como parámetro. El método
GetCreationTime( ) nos devuelve un tipo Date con la fecha de creación del archivo.

Por otro lado, si queremos obtener información adicional sobre un archivo, como
su nombre, extensión, ruta, etc., instanciaremos un objeto FileInfo( ), pasando al
constructor una cadena con el nombre del archivo, y utilizaremos algunas de sus
propiedades como Name, Extensión, DirectoryName. Veamos una muestra de todo
esto en el Código fuente 421.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 444


Dim sNombreFich As String
Dim iOperacion As Integer
Dim oFInfo As FileInfo

Console.WriteLine("Introducir ruta y archivo")


sNombreFich = Console.ReadLine()

Console.WriteLine("Fecha creación archivo: {0}", _


File.GetCreationTime(sNombreFich))

oFInfo = New FileInfo(sNombreFich)

Console.WriteLine("Introducir el número de operación a realizar:")


Console.WriteLine("1 - Copiar")
Console.WriteLine("2 - Mover")
Console.WriteLine("3 - Borrar")
iOperacion = Console.ReadLine()

Select Case iOperacion


Case 1
File.Copy(sNombreFich, "\pruebas\distinto" & oFInfo.Extension)

Case 2
Console.WriteLine("Vamos a mover el archivo {0}", oFInfo.Name)
Console.WriteLine("que está en la ruta {0}", oFInfo.DirectoryName)
File.Move(sNombreFich, "\pruebas\" & oFInfo.Name)
Console.WriteLine("Completado")
Console.ReadLine()
Case 3
File.Delete(sNombreFich)

End Select

Manipulación de archivos mediante Directory y DirectoryInfo

Las clases Directory y DirectoryInfo contienen métodos y propiedades para crear,


borrar, copiar y mover directorios, así como otra serie de tareas para su manejo y
obtención de información.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 445


Al igual que sucedía con las clases del anterior apartado, los miembros de Directory son
compartidos, mientras que los de DirectoryInfo son de instancia; esta es su principal
diferencia.

En el ejemplo del Código fuente, el método Exists( ) comprueba la existencia de un


directorio, y en caso afirmativo, obtenemos su última fecha de uso mediante
GetLastAccessTime( ). Seguidamente obtenemos un array String con su lista de archivos
mediante GetFiles( ), y creamos un subdirectorio de respaldo con CreateSubdirectory( ).
En caso de que el directorio no exista, lo creamos con CreateDirectory( ).

Dim sNombreDir As String


Dim Archivos() As String
Dim Archivo As String
Dim oDirInfo As DirectoryInfo

Console.WriteLine("Introducir un nombre de directorio")


sNombreDir = Console.ReadLine()
If Directory.Exists(sNombreDir) Then
Console.WriteLine("Fecha último acceso: {0}", _
Directory.GetLastAccessTime(sNombreDir))
Console.WriteLine("Archivos del directorio {0}", sNombreDir)
Archivos = Directory.GetFiles(sNombreDir)
For Each Archivo In Archivos
Console.WriteLine(Archivo)
Next
Else
oDirInfo = New DirectoryInfo(sNombreDir)
oDirInfo.CreateSubdirectory("bak")
Directory.CreateDirectory(sNombreDir)
Console.WriteLine("No existía el directorio, se acaba de crear")
End If

Para obtener el directorio actual de ejecución, disponemos del método


GetCurrentDirectory( ), mientras que si queremos subir al directorio de nivel superior,
tenemos el método GetParent( ), que devuelve un tipo DirectoryInfo, con el que
podemos, por ejemplo, mostrar su nombre completo mediante la propiedad FullName,
y fecha de creación con CreationTime. Veamos el Código fuente

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 446


Dim sNombreDir As String
Dim oDirInfo As DirectoryInfo
' obtenemos el directorio actual de ejecución
sNombreDir = Directory.GetCurrentDirectory()
Console.WriteLine("Directorio actual: {0}", sNombreDir)
' obtenemos el directorio padre del actual,
' y mostramos información de dicha directorio
oDirInfo = Directory.GetParent(sNombreDir)
Console.WriteLine("Directorio padre y fecha de creación {0}{1}{2}{3}", _
ControlChars.CrLf, oDirInfo.FullName, _
ControlChars.CrLf, oDirInfo.CreationTime)

En el siguiente ejemplo, el método GetDirectories( ) devuelve un array de cadenas, con los


nombres de los subdirectorios que se encuentran dentro del directorio pasado como
parámetro a este método. A continuación, mediante el método Move( ), cambiamos de
lugar un directorio; con Delete( ) borramos otro de los directorios. Observe el lector,
cómo utilizando de forma combinada CType( ), Directory.GetFiles( ), y un elemento
del array que contiene la lista de directorios, creamos una expresión que nos permite
averiguar, si en un determinado directorio hay o no archivos. Ver el Código fuente.

Dim sNombreDir As String


Dim oDirInfo As DirectoryInfo
Dim sDirectorios() As String
Dim sDirectorio As String
Console.WriteLine("Introducir un nombre de directorio")
sNombreDir = Console.ReadLine()
' obtener directorios del directorio especificado
sDirectorios = Directory.GetDirectories(sNombreDir)
' comprobar que el directorio contiene a su vez
' varios directorios; en caso negativo, finalizar
If Not (sDirectorios.Length > 1) Then
Console.WriteLine("El directorio especificado debe contener al menos dos
subdirectorios")
Console.ReadLine()
Exit Sub
End If

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 447


' mostrar nombres de directorios
For Each sDirectorio In sDirectorios
Console.WriteLine(sDirectorio)
Next

' mover uno de los directorios a otra ubicación del disco actual
Directory.Move(sDirectorios(0), "\temp\BIS")

' borrar otro de los directorios;


' el directorio a borrar debe estar vacío;
' comprobar con la siguiente expresión si dicho
' directorio contiene o no archivos
If (CType(Directory.GetFiles(sDirectorios(1)), String()).Length() > 0) Then
Console.WriteLine("No se puede borrar el directorio: {0} - " & _
"contiene archivos", sDirectorios(1))
Else
Directory.Delete(sDirectorios(1))
End If

Console.WriteLine("Completado")
Console.ReadLine()

La clase Path

Esta clase nos proporciona un conjunto de campos y métodos compartidos, para la


obtención de información y manipulación de rutas de archivos. El Código fuente muestra
un ejemplo en el que, una vez introducido un directorio, se muestra la información de
cada uno de sus archivos, en lo que respecta a los métodos de esta clase.

Console.WriteLine("Introducir nombre de directorio")


Dim sDirectorio As String
sDirectorio = Console.ReadLine()
Dim sArchivos() As String
sArchivos = Directory.GetFiles(sDirectorio)
Console.WriteLine("Datos sobre archivos obtenidos del objeto Path")
Console.WriteLine("===========================================")
Dim sArchivo As String
For Each sArchivo In sArchivos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 448


Console.WriteLine("GetDirectoryName() {0}", Path.GetDirectoryName(sArchivo))
Console.WriteLine("GetExtension() {0}", Path.GetExtension(sArchivo))
Console.WriteLine("GetFileName() {0}", Path.GetFileName(sArchivo))
Console.WriteLine("GetFileNameWithoutExtension() {0}",
Path.GetFileNameWithoutExtension(sArchivo))
Console.WriteLine("GetFullPath() {0}", Path.GetFullPath(sArchivo))
Console.WriteLine()
Next
Console.ReadLine()

Monitorización del sistema de archivos con FileSystemWatcher

Esta clase contiene los mecanismos necesarios, que nos van a permitir la creación de
objetos que actúen como observadores de los sucesos que ocurran en el sistema de
archivos de un equipo local o remoto en cuanto a la creación, borrado, modificación, etc.,
de archivos y directorios.

La creación de este proceso de vigilancia podemos dividirla en dos partes:


instanciación y configuración del propio objeto FileSystemWatcher; y la escritura
de los procedimientos manipuladores de los diversos eventos que pueden ocurrir sobre
los archivos y directorios.

Para facilitar la escritura de los manipuladores de evento, podemos declarar una variable
de esta clase a nivel de módulo, con la palabra clave WithEvents. Ver Código fuente

Module Module1
Private WithEvents oFSW As FileSystemWatcher
Sub Main()
'....
'....

Declarado el objeto FileSystemWatcher, lo instanciaremos y asignaremos valor a las


propiedades mencionadas a continuación, que nos permitirán configurar el modo de
observación que realizará este objeto sobre los archivos.

Path. Tipo String. Contiene la ruta de la unidad de disco sobre la que se


efectuará la monitorización.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 449


Filter. Tipo String. Contiene el tipo de fichero que se va a observar, admitiendo
los caracteres comodín; por ejemplo: “*.*”, “*.txt”.

IncludeSubdirectories. Tipo Boolean. Establece si se van a monitorizar los


subdirectorios de la ruta especificada en la propiedad Path. El valor True incluye los
subdirectorio, mientras que False no los incluye.

EnableRaisingEvents. Tipo Boolean. Activa el proceso de observación sobre el


sistema de archivos, teniendo en cuenta la configuración establecida en
las demás propiedades mencionadas arriba. El valor True pone en marcha el
mecanismo de observación, mientras que el valor False lo detiene.
Veamos un ejemplo de estas propiedades en el Código fuente

Sub Main()
' instanciar objeto FileSystemWatcher
oFSW = New FileSystemWatcher()
' configurar objeto
oFSW.Path = "C:\pruebas"
oFSW.Filter = "*.txt"
oFSW.IncludeSubdirectories = True

' activar
oFSW.EnableRaisingEvents = True

' mientras que no pulsemos S, el objeto inspeccionará


' el sistema de archivos del equipo
While (Console.ReadLine() <> "S")
End While
End Sub

Para completar este proceso que estamos describiendo, sólo nos queda escribir los
procedimientos que van a ejecutarse cuando se realice la creación, borrado,
modificación, etc., de un archivo.

Puesto que hemos declarado la variable FileSystemWatcher a nivel del módulo


de código, seleccionaremos dicha variable en la lista desplegable Nombre de clase,
del editor de código. Seguidamente, abriremos la lista Nombre de método, también
del editor; seleccionando el evento a codificar.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 450


Las anteriores acciones, crearán el procedimiento de evento correspondiente, pero
vacío, por lo que tendremos que escribir el código que queramos ejecutar en
respuesta a tal evento. La lista de parámetros de este procedimiento consiste en un
tipo Object, que contiene la referencia al objeto FileSystemWatcher que originó el
evento; y un tipo FileSystemEventArgs, que contiene información adicional sobre el
evento ocurrido, como el nombre y ruta del archivo.

El Código fuente muestra los procedimientos de evento que se ejecutarán cuando se


cree o borre un archivo.

' al crear un fichero se ejecutará este procedimiento de evento


Public Sub oFSW_Created(ByVal sender As Object, ByVal e As
System.IO.FileSystemEventArgs) Handles oFSW.Created
Console.WriteLine("Se ha creado un archivo : {0}", e.FullPath)
End Sub

' al borrar un fichero se ejecutará este procedimiento de evento


Public Sub oFSW_Deleted(ByVal sender As Object, ByVal e As
System.IO.FileSystemEventArgs) Handles oFSW.Deleted
Console.WriteLine("Se ha producido el borrado: {0}", e.FullPath)
End Sub

Ajuste preciso de filtros para el monitor de archivos

Si queremos realizar un filtro más puntual, por ejemplo, cuando hagamos cambios sobre
los archivos a monitorizar, la clase FileSystemWatcher dispone de la propiedad
NotifyFilter, que contiene una enumeración de tipo NotifyFilters, cuyos valores
podemos combinar para que sólo se detecten los cambios al modificar el tamaño y/o
la última escritura sobre un archivo. La Figura muestra un ejemplo del uso de esta
propiedad.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 451


Uso de filtros de notificación para un objeto FileSystemWatcher.

Establecer el procedimiento de evento con AddHandler

Además de crear los procedimientos de evento de la forma descrita en apartados


anteriores, podemos emplear una técnica más flexible, que nos permite conectar
los eventos del objeto con sus manipuladores, utilizando la palabra clave AddHandler.
El Código fuente muestra un ejemplo de esta situación.

Sub Main()
' instanciar objeto FileSystemWatcher
Dim oFSW As New FileSystemWatcher()

' configurar objeto


oFSW.Path = "C:\pruebas"
oFSW.Filter = "*.txt"
oFSW.IncludeSubdirectories = True

' conectamos manualmente los eventos del objeto


' con los procedimientos manipuladores de esos eventos
AddHandler AddressO oFSW_Created
oFSW.Created,
AddHandler f
AddressO CambioProducido
oFSW.Changed, f
' activar

oFSW.EnableRaisingEvents = True
' mientras que no pulsemos S, el objeto inspeccionará
' el sistema de archivos del equipo
While (Console.ReadLine() <> "S")

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 452


End While
End Sub

Public Sub oFSW_Created(ByVal sender As Object, ByVal e As


System.IO.FileSystemEventArgs)
Console.WriteLine("Se ha creado un archivo: {0}", e.FullPath)
End Sub

Public Sub CambioProducido(ByVal emisor As Object, ByVal argumentos As


FileSystemEventArgs)
Console.WriteLine("Se ha cambiado el archivo: {0}", argumentos.FullPath)
End Sub

Observe el lector, que para el nombre del procedimiento manipulador de evento,


podemos emplear tanto el formato que utiliza el editor de código, como otro nombre
cualquiera.

Para el evento de creación de archivo hemos utilizado el formato que usa también el
editor, consistente en poner el nombre de objeto, guión bajo, y nombre de evento:
oFSW_Created( ).

Sin embargo para el evento de modificación de archivo hemos utilizado un nombre que
no se ajusta en absoluto al formato del editor: CambioProducido( ).

Consideraciones sobre la ruta de archivos

El modo en que asignemos a la propiedad Path del objeto FileSystemWatcher, la cadena


con la ruta a inspeccionar, influirá en el modo en que recuperemos la información del
evento en el procedimiento manipulador correspondiente.

Si asignamos a Path la ruta, sin especificar la unidad de disco, al intentar utilizar la


propiedad FullName del objeto FileSystemEventArgs, en el procedimiento de evento, se
producirá un error. Ver el Código fuente

Sub Main()
'....
oFSW.Path = "\pruebas"
'....

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 453


End Sub

Public Sub oFSW_Created(ByVal sender As Object, ByVal e As


System.IO.FileSystemEventArgs)
' al intentar utilizar la propiedad FullPath ocurrirá un error
Console.WriteLine("Se ha creado un archivo: {0}", e.FullPath)
End Sub

Para que en el anterior ejemplo no se produzca un error, debemos indicar también la


letra de unidad correspondiente al asignar la ruta a Path. Ver Código fuente

oFSW.Path = "C:\pruebas"

Detección con espera, de eventos producidos sobre archivos

El método WaitForChanged( ) de la clase FileSystemWatcher, devuelve un objeto


de tipo WaitForChangedResult, el cual efectúa una parada en la ejecución, quedando a
la espera de que ocurra un determinado evento sobre el sistema de archivos. Una vez
que dicho evento se produzca, se continuará la ejecución del programa.

El tipo de evento que ponemos a la espera, lo definimos pasando como parámetro


al método WaitForChanged( ), un valor de la enumeración WatcherChangeTypes.
Veamos un ejemplo en el Código fuente

Dim oFSW As New FileSystemWatcher()


'....
' crear un objeto de espera para un evento
Dim oWFCR As WaitForChangedResult
oWFCR = oFSW.WaitForChanged(WatcherChangeTypes.Created)
Console.WriteLine("Se ha creado el archivo: {0}", oWFCR.Name)
'....

Manipulación de archivos mediante funciones específicas de Visual Basic

Como comentábamos al comienzo de este tema, en anteriores versiones de VB, el


programador tenía a su disposición un grupo de instrucciones como Open, Input, Write,
etc., para la lectura y escritura de información en archivos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 454


Por cuestiones de compatibilidad y migración de aplicaciones existentes, estas
instrucciones han sido transformadas en funciones, para facilitar su manejo.

Funciones como FileOpen( ), para abrir un archivo; FileClose( ), para cerrarlo; LineInput(
), para leer una línea de texto de un archivo, etc, son las que permiten en la actual versión
del lenguaje, realizar las operaciones que anteriormente efectuábamos mediante sus
correspondientes instrucciones.

El Código fuente muestra un pequeño ejemplo, en el que se abre un fichero de texto y


se lee su contenido utilizando algunas de estas funciones. Consulte el lector, la
documentación de la plataforma, para una mayor información.

Dim iNumArchivo As Integer


' obtener número de manipulador de archivo libre
iNumArchivo = FreeFile()

' abrir archivo para lectura


FileOpen(iNumArchivo, "\cubo\notas.txt", OpenMode.Input)

Dim sLinea As String


' recorrer archivo hasta el final
While Not EOF(iNumArchivo)
' leer una línea del archivo
sLinea = LineInput(iNumArchivo)
Console.WriteLine(sLinea)
End While

' cerrar el archivo


FileClose(iNumArchivo)
Console.ReadLine()

A pesar de que estas funciones nos permiten la manipulación de ficheros, debemos tener
muy presente que se trata de elementos fundamentalmente proporcionados para
compatibilidad con versiones anteriores, por lo que se recomienda que cuando
tengamos que hacer cualquier tipo de operación con archivos en cuanto a su lectura,
escritura, manipulación, etc., utilicemos las clases del espacio de nombres IO.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 455


13.- Ensamblados en Visual Basic net
Los ensamblados componen la unidad fundamental de implementación, control de
versiones, reutilización, ámbito de activación y permisos de seguridad en una aplicación
basada en .NET. Los ensamblados adoptan la forma de un archivo ejecutable (.exe) o un
archivo de biblioteca de vínculos dinámicos (.dll), y constituyen unidades de creación de
.NET Framework. Proporcionan a Common Language Runtime la información que necesita
para estar al corriente de las implementaciones de tipos. Un ensamblado puede entenderse
como una colección de tipos y recursos que forman una unidad lógica de funcionalidad y
que se generan para trabajar conjuntamente.

En Visual Basic, se utiliza el contenido de los ensamblados y se agregan referencias a dichos


ensamblados, de forma muy parecida a como se utilizaban las bibliotecas de tipos en
versiones anteriores de Visual Basic. No obstante, lo que distingue a los ensamblados de los
archivos .exe o .dll de versiones anteriores de Windows es que pueden contener toda la
información que antes se encontraba en una biblioteca de tipos, además de información de
todo aquello que sea necesario para utilizar la aplicación o el componente.

Manifiesto del ensamblado


Todos los ensamblados contienen un manifiesto del ensamblado. Éste es similar a una tabla
de contenido, y contiene la siguiente información:

 La identidad del ensamblado (nombre y versión).


 Una tabla de archivos que describe el resto de archivos que componen el
ensamblado, por ejemplo, otros ensamblados creados por el usuario de los que
dependa el archivo .exe o .dll, e incluso archivos de mapa de bits o archivos Léame.
 Una lista de referencias de ensamblado, es decir, una lista de todas las dependencias
externas, archivos .dll u otros archivos necesarios para la aplicación que otros
usuarios hayan podido crear. Las referencias de ensamblado contienen referencias
a objetos globales y privados. Los objetos globales residen en la caché de
ensamblados global, un área disponible para otras aplicaciones, parecida al
directorio System32. El espacio de nombres Microsoft.VisualBasic es un ejemplo de
un ensamblado en la caché de ensamblados global. Los objetos privados deben
encontrarse en un directorio del mismo nivel o inferior al directorio de instalación
de la aplicación.

Dado que los ensamblados contienen información del contenido, la versión y las
dependencias, las aplicaciones que se crean con Visual Basic no dependen de los valores del

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 456


Registro para que funcionen correctamente. Los ensamblados reducen los conflictos de los
archivos DLL y hacen que las aplicaciones sean más seguras y más fáciles de implementar.
En muchos casos es posible instalar una aplicación basada en .NET simplemente copiando
los archivos de la aplicación en el equipo de destino.

Referencias
Para utilizar un ensamblado, debe agregar una referencia a él, tal como se describe en
Cómo: Agregar o quitar referencias en Visual Studio (Visual Basic). Luego, utiliza la
instrucción Imports para elegir el espacio de nombres de los elementos que desea utilizar,
tal como se describe en Referencias y la instrucción Imports. Una vez que se haya hecho
referencia a un ensamblado y se haya importado, todas las clases, propiedades, métodos y
otros miembros accesibles de su espacio de nombres están disponibles para la aplicación
como si su código formara parte del archivo de código fuente. Un ensamblado individual
puede contener varios espacios de nombres, y cada espacio de nombres puede contener
una agrupación de elementos distinta, incluidos otros espacios de nombres.

Crear ensamblados
Se pueden crear ensamblados de un único archivo o de varios archivos mediante un IDE,
como Visual Studio 2005 o mediante los compiladores y herramientas proporcionados en
Kit de desarrollo de software de Windows (SDK). El ensamblado más sencillo es un único
archivo que tiene un nombre sencillo y se carga en un solo dominio de aplicación. A este
ensamblado no pueden hacer referencia otros ensamblados de fuera del directorio de la
aplicación. En este ensamblado no se pueden comprobar las versiones. Para desinstalar la
aplicación que forma el ensamblado, no hay más que eliminar el directorio en que reside.
Muchos programadores no necesitan más que un ensamblado con estas características para
implementar una aplicación.

Se puede crear un ensamblado con varios archivos a partir de varios módulos de código y
archivos de recursos. También se puede crear un ensamblado que puedan compartir varias
aplicaciones. Un ensamblado compartido debe tener un nombre seguro y se puede
implementar en la caché de ensamblados global.

Existen varias opciones para agrupar módulos de código y recursos en ensamblados,


dependiendo de los siguientes factores:

 Control de versiones
Agrupe módulos que deban tener la misma información de versión.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 457


 Implementación

Agrupe módulos de código y recursos compatibles con el modelo de


implementación.

 Reutilización

Agrupe módulos si se pueden utilizar juntos de forma lógica con la misma finalidad.
Por ejemplo, un ensamblado formado por tipos y clases que se usan raramente en
el mantenimiento de programas se pueden poner en el mismo ensamblado.
Además, los tipos que se vayan a compartir entre varias aplicaciones se deben
agrupar en un ensamblado, que se debe firmar con un nombre seguro.

 Seguridad

Agrupe módulos que contengan tipos que requieran los mismos permisos de
seguridad.

 Ámbito

Agrupe módulos que contengan tipos que sólo pueda ver el mismo ensamblado.

Si los ensamblados de Common Language Runtime van a estar disponibles para aplicaciones
COM no administradas hay que tener en cuenta factores especiales. Para obtener más
información sobre cómo trabajar con código no administrado, vea Exponer componentes
de .NET Framework en COM.

Cómo: Crear y utilizar ensamblados

Un ensamblado está formado por uno o más archivos .exe o .dll que componen una
aplicación de Visual Studio. Los ensamblados se crean de forma automática cuando se
compilan archivos de código fuente de Visual Basic.

Nota:
Los cuadros de diálogo y comandos de menú que se ven pueden diferir de los descritos
en la Ayuda, dependiendo de los valores de configuración o de edición activos. Para
cambiar la configuración, elija la opción Importar y exportar configuraciones en el menú
Herramientas. Para obtener más información, vea Valores de configuración de Visual
Studio.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 458


Para crear un ensamblado

 Para compilar la aplicación, haga clic en Generar en el menú Generar o bien


genérela desde la línea de comandos, mediante el compilador de la línea de
comandos. Para obtener información detallada sobre la generación de
ensamblados desde la línea de comandos, vea Generar desde la línea de comandos
(Visual Basic).

Para agregar una referencia a otro ensamblado

 Haga clic en el comando Agregar referencia del menú Proyecto y seleccione el


ensamblado que desee usar. Para obtener información detallada, vea Cómo:
Agregar o quitar referencias en Visual Studio (Visual Basic).

Para utilizar objetos en otro ensamblado

 Especifique el nombre completo del objeto o utilice un alias que se haya definido
para el objeto por medio de una instrucción Imports. Para obtener información
detallada acerca de los nombres completos, vea Espacios de nombres en Visual
Basic. Para obtener información detallada sobre la adición de referencias y la
utilización de la instrucción Imports, vea Referencias y la instrucción Imports.

Cómo: Generar un ensamblado de un solo archivo


Un ensamblado de un único archivo, que es el tipo de ensamblado más sencillo, contiene la
información e implementación del tipo, además del manifiesto del ensamblado. Para crear
un ensamblado de un único archivo se pueden usar compiladores de la línea de comandos
o Visual Studio 2005. De forma predeterminada, el compilador crea un archivo de
ensamblado con la extensión .exe.

Nota:
Visual Studio 2005 para C# y Visual Basic sólo se puede utilizar para crear ensamblados de
un solo archivo. Si se desea crear ensamblados de múltiples archivos, se deben usar
compiladores de la línea de comandos o Visual Studio 2005 para Visual C++.

Los procedimientos siguientes muestran cómo se crean ensamblados de un único archivo


mediante compiladores de la línea de comandos.

Para crear un ensamblado con la extensión .exe

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 459


 En el símbolo del sistema, escriba el siguiente comando:

<comando del compilador> <nombre del módulo>

En este comando, comando del compilador es el comando del compilador para el


lenguaje utilizado en el módulo de código y nombre del módulo es el nombre del
módulo de código que se va a compilar en el ensamblado.

En el ejemplo siguiente se crea un ensamblado denominado myCode.exe desde un módulo


de código denominado myCode.

C# VB
csc myCode.cs

Para crear un ensamblado con una extensión .exe y especificar el nombre del
archivo de resultados

 En el símbolo del sistema, escriba el siguiente comando:

<comando del compilador> /out:<nombre de archivo> <nombre del módulo>

En este comando, comando del compilador es el comando del compilador para el


lenguaje usado en el módulo de código, nombre de archivo es el nombre del archivo
de salida y nombre del módulo es el nombre del módulo de código que se va a
compilar en el ensamblado.

En el ejemplo siguiente se crea un ensamblado denominado myAssembly.exe desde un


módulo de código denominado myCode.

C# VB
csc /out:myAssembly.exe myCode.cs
Crear ensamblados de biblioteca
Un ensamblado de biblioteca es parecido a una biblioteca de clases. Contiene tipos a los
que harán referencia otros ensamblados, pero no tiene un punto de entrada para comenzar
la ejecución.

Para crear un ensamblado de biblioteca

 En el símbolo del sistema, escriba el siguiente comando:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 460


<comando del compilador> /t:library <nombre del módulo>

En este comando, comando del compilador es el comando del compilador para el


lenguaje utilizado en el módulo de código y nombre del módulo es el nombre del
módulo de código que se va a compilar en el ensamblado. También se pueden usar
otras opciones de compilador, por ejemplo /out:.

En el ejemplo siguiente se crea un ensamblado de biblioteca denominado


myCodeAssembly.dll desde un módulo de código denominado myCode.

C# VB
csc /out:myCodeLibrary.dll /t:library myCode.cs

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 461


14 .-Crear un proyecto de instalación (Setup) para
Windows
Introducción:
Aunque como sabemos con .NET Framework no es necesario crear programas (o
proyectos) de instalación, dado que este nuevo entorno facilita la forma de distribuir las
aplicaciones mediante lo que se llama instalación XCOPY (o FTP), es decir, podemos copiar
nuestras aplicaciones creadas con cualquier lenguaje .NET simplemente copiando el
directorio con el ejecutable y las librerías de las que depende al equipo en el que queremos
usarlo y ya funcionará. Pero funcionará si el equipo de destino ya tiene instalada el
"runtime" de .NET Framework, y esto es así porque ese runtime ya incluye todo lo que
necesitamos para que nuestra aplicación funcione. Aunque en ocasiones, es posible que
además de esas librerías "básicas" (incluidas en el runtime del .NET), necesitemos copiar
nuevas librerías, en ese caso simplemente copiaremos las librerías extras dentro del propio
directorio de nuestra aplicación y... ¡todo funcionará!
Esto es así porque no necesitamos registrar ningún componente para poder usarlo con
nuestra aplicación, por tanto... realmente no necesitamos crear ningún proyecto de
instalación, pero... si es eso lo que quieres hacer, para facilitarte las cosas, no es lo mismo
tener que copiar cosas en una carpeta que distribuir un instalador y que sea el propio
usuario el que se encargue del proceso de instalación, así como de eliminar dicha
instalación cuando le apetezca.

También habrá ocasiones en las que tengamos que instalar una librería "compartida", en
esos casos, la creación de un proyecto de instalación nos facilitará el registro (o copia) de
esa librería en el GAC (Global Assembly Cache, caché de ensamblado global) que es una
carpeta especial usada por el .NET Framework en la que estarán todas las librerías
compartidas del .NET Framework.

Nota:
Para que una librería se pueda usar de forma global, ésta debe estar firmada con un Strong
Name (nombre seguro). Si quieres saber más cómo crear (o firmar) una librería con nombre
seguro.

Aviso importante:

Una cosa que debes saber antes de seguir, es que creando un proyecto de instalación, no
se instala el runtime del .NET Framework.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 462


Cuando creamos el proyecto de instalación, éste se encargará de instalar nuestra aplicación
y los demás ficheros (archivos) que le indiquemos, pero NO instalará el runtime.

El runtime (o redistribuible) de .NET Framework debemos instalarlo por nuestra cuenta


ANTES de instalar nuestra aplicación.

Bien, sabiendo esto, sigamos con lo nuestro.

Vamos a ver cómo crear un proyecto de instalación.

Para que quede la cosa clara, primero tendremos que tener abierto el proyecto con el
ejecutable (o aplicación) que queremos distribuir, (si quieres, puedes crear un nuevo
proyecto, simplemente para probar).

Supongamos que el proyecto que queremos distribuir se llama: ClienteSetup y lo tenemos


abierto en el Visual Studio .NET (la versión usada para este artículo es la versión 2002, pero
los pasos a seguir serán los mismos para versiones posteriores).

Proyecto de instalación usando el Asistente:

Del menú Archivo, seleccionaremos la opción Agregar proyecto>Nuevo proyecto..., se


mostrará el cuadro de diálogo de añadir nuevo proyecto, del panel izquierdo
seleccionaProyectos de instalación e implementación, en el panel derecho se mostrarán
los posibles tipos de proyectos, seleccionaremos Asistente para proyectos de
instalación (después veremos cómo crear un proyecto de instalación sin usar el asistente).
Este cuadro de diálogo podemos verlo en la siguiente figura (Figura 1):

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 463


Figura 1, cuadro de diálogo Agregar nuevo proyecto

Se mostrará el Asistente para proyectos de instalación (iremos viendo las distintas pantallas
que se irán mostrando), en la figura 2, tenemos la primera de las 5 pantallas del asistente:

Figura 2, Primera pantalla del asistente

En esta pantalla, simplemente pulsaremos en Siguiente, para que se muestre la siguiente


pantalla del asistente:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 464


Figura 3, seleccionar el tipo de proyecto

Aquí dejaremos la opción que hay seleccionada, ya que lo que queremos es crear un
proyecto de instalación para una aplicación de Windows.

Pulsamos en Siguiente

En la cuarta pantalla del asistente, se nos preguntará qué es lo que queremos incluir en el
proyecto de instalación, tal como se muestra en la Figura 4:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 465


Figura 4, indicar los resultados a incluir en el proyecto de instalación

Si sólo queremos distribuir el ejecutable, seleccionaremos la primera de las opciones:


Resultado principal del "Nombre del proyecto", en caso de que queramos incluir también
el código fuente, seleccionaremos la última de las opciones que se indican, pero por ahora
sólo seleccionaremos la primera de ellas.

Una vez realizada la selección, pulsaremos en Siguiente.

Se nos mostrará la siguiente pantalla (ver la Figura 5), desde aquí podemos añadir más
archivos, como por ejemplo imágenes y otros ejecutables, bases de datos, etc., que nuestro
programa necesite; en caso de que así sea, pulsaremos en el botón Agregar... y
seleccionaremos el o los ficheros extras que queramos.
Si no tenemos que añadir nada más, (o cuando hayamos terminado de agregar los ficheros
que queramos), pulsaremos en Siguiente para finalizar el asistente.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 466


Figura 5

Una vez terminado, el asistente nos mostrará información sobre las cosas que hemos
indicado, tal como se muestra en la Figura 6:

Figura 6

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 467


Una vez que hemos terminado con el asistente, (después de pulsar en el botón Finalizar),
tendremos un nuevo proyecto en la solución del proyecto que queremos distribuir. Esto lo
podemos comprobar en el Explorador de soluciones, tal como podemos ver en la figura 7:

Figura 7, el explorador de soluciones

Lo único que nos queda es generar el proyecto Setup1 y ya tendremos creado el proyecto
de instalación, el cual se encontrará en la carpeta indicada para almacenar ese proyecto de
instalación y dependiendo que estemos en modo Debug o Release, tendremos que navegar
hasta la carpeta correspondiente.

Dentro de esa carpeta se incluirán estos ficheros:

Figura 8, los ficheros generados con el instalador

Realmente sólo necesitaremos el fichero con la extensión .msi, ya que el resto es para los
casos de que el equipo de destino no disponga del Windows Installer 2.0, si estamos seguro
de que es así, sólo necesitaremos usar el fichero Setup1.msi, si no estamos seguro de que
tenga el Windows Installer 2.0, usaremos los 5 ficheros incluidos en el directorio.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 468


Nota:
Si seleccionamos Propiedades del proyecto de instalación (el último icono mostrado al
seleccionar el proyecto de instalación del Explorador de soluciones, ver figura 7), podemos
cambiar esta generación de tantos ficheros "de soporte", es decir, podemos cambiar la
configuración para que sólo se genere el fichero con extensión .msi

Proyecto de instalación sin usar el asistente:

Si te decides por seleccionar un proyecto de instalación sin usar el asistente, sigue estos
pasos para crearlo:

1- Del cuadro de diálogo de Agregar nuevo proyecto (ver figura 1), selecciona Proyecto de
instalación.

2- Se agregará un nuevo proyecto de instalación.

3- Selecciona el proyecto del Explorador de soluciones, pulsa con el botón secundario del
ratón y del menú desplegable selecciona la opción Agregar>Resultados del proyecto.

4- Se mostrará una ventana como la de la figura 9:

Figura 9, agregar grupo de resultados del proyecto

5- Seleccionaremos de la lista desplegable el proyecto que queremos usar y pulsaremos en


Aceptar.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 469


A partir de este momento, el resto será como si hubiésemos usado el asistente.

También podemos usar esta última forma de agregar resultados (o más cosas) en el caso de
que queramos distribuir más de un proyecto, ya que en esa lista desplegable se mostrarán
cada uno de los proyectos que tengamos en nuestra solución (o grupo de proyectos).

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 470


BASES DE DATOS EN VISUAL BASIC NET

1.- Acceso a Datos con ADO.NET en Visual Basic


1.1.- Que es una base de datos
1.2.- Tipos de bases de datos
1.3.- Lenguaje de consulta estructurado
1.4.- Sentencias SQL básicas
1.5.- Acercandonos a ADO.NET
1.6.- SystemData
1.7.- Los proveedores de acceso a datos
1.8.- El concepto DataBinding
1.9.- Otras consideraciones
1.10.- El paradigama de conexión
2.- Trabajando con Datos
2.1.- Conociendo el objeto DataReader
2.2.- Un primer contacto con el objeto DataReader
2.3.- ¿Trabaja DatReader en un ambiente conectado realmente?
2.4.- Usando DataSource con DataReader
2.5.- Usando componentes de acceso a datos de .NET
2.6.- Esquema general de la estrucutra desconectada de acceso a datos
2.7.- Conociendo el objeto DataAdapter
2.8.- Insertando datos a través del Objeto DataAdapter
2.9.- Actualizando datos a través del objeto DataAdapter
2.10.- Eliminando datos a través del objeto DataAdapter
2.11.- ¿Qué son los datos Maestro Detalle?
2.12.- Configurando la fuente de datos
2.13.- Preparando el origen de datos
2.14.- Inscrustando los datos Maestro Detalle
2.15.- Manipulando los datos.

ADENDUM

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 471


Acceso a datos con ADO.NET en Visual Basic
1.1 Que es una base de datos

Una base de datos es un sistema formado por un conjunto de datos almacenados en discos
que permiten el acceso directo a ellos y un conjunto de programas que manipulen ese
conjunto de datos (S.G.B.D. Sistema de Gestión de Bases de Datos). Cada base de datos se
compone de una o más tablas que guarda un conjunto de datos. Cada tabla tiene una o más
columnas y filas. Las columnas guardan una parte de la información sobre cada elemento que
se quiere guardar en la tabla, cada fila de la tabla conforma un registro. Entre las principales
características se pueden mencionar:
Independencia lógica y física de los datos.
Redundancia mínima.
Acceso concurrente por parte de múltiples usuarios.
Integridad de los datos.
Consultas complejas optimizadas.
Seguridad de acceso y auditoria.
Respaldo y recuperación.
Acceso a través de lenguajes de programación estándar.

1.2 Tipos de bases de datos


1.2.1 Relacionales

Son las que más se utilizan. Las bases de datos relacionales son un conjunto de tablas
relacionadas entre sí, cada tabla está definida por una serie de campos. Los campos forman
las columnas de las tablas; definen el tipo y la variedad de sus datos. Las filas de datos se
denominan registros (tuplas), cada tipo definido en un registro se le denomina atributo. Las
tablas pertenecientes a una base de datos pueden relacionarse entre sí utilizando campos clave
comunes entre las tablas.

1.2.2 Enfoque orientado a objetos

El esquema de una base de datos por objetos está representado por un conjunto de clases que
definen las características y el comportamiento de los objetos que poblarán la base de datos.
Con una base de datos orientada a objetos, los objetos memorizados en la base de datos
contienen tanto los datos como las operaciones posibles con tales datos. En cierto sentido, se
podrá pensar en los objetos como en datos a los que se les ha puesto una inyección de
inteligencia que les permite saber cómo comportarse, sin tener que apoyarse en aplicaciones
externas.

1.3 Lenguaje de consulta estructurado

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 472


Es un lenguaje de base de datos normalizado, utilizado por los diferentes manejadores de
bases de datos para realizar determinadas operaciones sobre los datos o sobre la estructura
de los mismos.

El lenguaje SQL (Structure Query Languaje) está compuesto por comandos,


cláusulas, operadores y funciones de agregado. Estos elementos se combinan en las
instrucciones para crear, actualizar y manipular las bases de datos.
1.3.1 Comandos

Existen dos tipos de comandos SQL:

o DLL que permiten crear y definir nuevas bases de datos, campos e índices.
o DML que permiten generar consultas para ordenar, filtrar y extraer datos de la base
de datos.

Tabla 11.1 Comandos DLL y DML de SQL.


Comandos DLL
Comando Descripción
CREATE Utilizado para crear nuevas tablas, campos e índices
DROP Empleado para eliminar tablas e índices.
Utilizado para modificar las tablas agregando campos o
ALTER
cambiando la definición de los campos.
Comandos DML
Comando Descripción
Utilizado para consultar registros de la base de datos que
SELECT
satisfagan un criterio determinado.
Utilizado para cargar lotes de datos en la base de datos en una
INSERT
única operación.
UPDATE Utilizado para modificar los valores de los campos y registros
especificados.
DELETE Utilizado para eliminar registros de una tabla de una base de
datos.

1.3.2 Cláusulas

Las cláusulas son condiciones de modificación utilizadas para definir los datos que desea
seleccionar o manipular.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 473


Tabla 11.2 Clausulas SQL.

Cláusula Descripción
Utilizada para especificar la tabla de la cual se van a
FROM
seleccionar los registros.
Utilizada para especificar las condiciones que deben
WHERE
reunir los registros que se van a seleccionar.
Utilizada para separar los registros seleccionados en
GROUP BY
grupos específicos.
HAVING Utilizada para expresar la condición que debe satisfacer
cada grupo.
Utilizada para ordenar los registros seleccionados de
ORDER BY
acuerdo con un orden específico.

1.3.3 Operadores lógicos

Los operadores lógicos comprueban la veracidad de alguna condición. Éstos, como los
operadores de comparación, devuelven el tipo de datos Boolean con el valor TRUE o
FALSE

Tabla 11.3 Operadores lógicos SQL.

Operador Uso
Es el "y" lógico. Evalúa dos condiciones y devuelve un
AND
valor de verdad sólo si ambas son ciertas.
Es el "o" lógico. Evalúa dos condiciones y devuelve un
OR
valor de verdad si alguna de las dos es cierta.
NOT Negación lógica. Devuelve el valor contrario de la
expresión.
BETWEEN Utilizado para especificar un intervalo de valores.
LIKE Utilizado en la comparación de un patrón.
IN Utilizado para especificar registros de una base de datos.
ALL Devuelve True si el conjunto de comparaciones en verdad.

7.3.4 Operadores de comparación

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 474


Los operadores de comparación comprueban si dos expresiones son iguales. Se pueden
utilizar en todas las expresiones excepto en las de los tipos de datos text, ntext o image.

Tabla 11.4 Operadores de comparación SQL.

Operador Uso
< Menor que
> Mayor que
<> Distinto de
<= Menor o igual que
>= Mayor o igual que
= Igual que

1.3.5 Funciones de agregado

Las funciones de agregado realizan un cálculo sobre un conjunto de valores y devuelven un


solo valor. Si exceptuamos la función COUNT, todas las funciones de agregado ignoran los
valores NULL. Las funciones de agregado se suelen utilizar con la cláusula GROUP BY de
la instrucción SELECT.

Tabla 11.5 Funciones de agregado SQL.

Función Descripción
Utilizada para calcular el promedio de los valores de un
AVG
campo determinado.
COUNT Utilizada para devolver el número de registros de la
selección.
Utilizada para devolver la suma de todos los valores de
SUM
un campo determinado.
MAX Utilizada para devolver el valor más alto de un campo
especificado.
MIN Utilizada para devolver el valor más bajo de un campo
especificado.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 475


1.4 Sentencias SQL básicas

Se describirá muy brevemente algunas de las sentencias SQL para la manipulación de los
datos de una tabla llamada usuarios. Para ello utilizaremos la siguiente estructura:
Tabla : Estructura de los campos de la tabla usuarios.

Campo Tipo de Longitud


Dato
id Texto 15
Nombres Texto 20
apellidos Texto 20
dirección Texto 25
Teléfono Texto 20
Ciudad_nac Texto 20
Fecha_nac dateTime

Y que contiene la siguiente información:

Tabla : Información de la tabla usuarios.

Id Nombre Apellido Dirección Teléfono Ciudad_na Fecha_nac


s s c
100 Carlos Romero Cra 7 # 20-10 4152584 Bogota 01/02/198
0
101 María Castro Calle 25 # 25- 3692581 Cali 15/03/198
10 4
112 José Peláez Av. 35 # 32-45 1234567 Medellín 20/05/196
0
114 Cristian Vanega Cra 7 # 29-58 9874561 Manizales 31/08/197
s 4
116 Rosa Cetina Calle 17 # 21- 3571596 Buga 15/12/198
14 5
118 Andrés Vanega Tranvs 48 # 8527419 Bogota 10/04/197
s 22-10 8
130 Angélic Morales Cra 68 # 21-11 6549518 Medellín 20/06/198
a 1
150 Johana Duarte Cra 2 # 45-38 9637534 Bogota 12/06/198
8

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 476


170 Mario Vargas Calle 1 # 99-18 6598743 Medellín 28/08/198
0

1.4.1 Sentencia SELECT

La sentencia SQL que más se utiliza es la instrucción de selección SELECT. Como su


nombre lo indica es una instrucción que permite seleccionar información de una tabla. Su
formato es:
SELECT campos_tabla FROM nombre_tabla
A continuación se realizarán algunos ejemplos:
Para visualizar toda la información que contiene la tabla usuarios se puede incluir con la
instrucción SELECT el carácter “*‟ o cada uno de los campos de la tabla.
SELECT * FROM usuarios
O
SELECT identificación, nombres,…….. FROM usuarios

Para visualizar solamente la identificación del usuario

SELECT identificacion FROM usuarios

Si se desea obtener los registros cuya identificación sea menor o igual que 116, se debe
utilizar la cláusula WHERE que especifica las condiciones que deben reunir los registros que
se van a seleccionar.

SELECT * FROM usuarios WHERE identificación<=”116”

Si se desea obtener los registros cuyos nombres sean Andrés o Cristian, se debe utilizar el
operador IN que especifica registros de una tabla.

SELECT nombres FROM usuarios WHERE nombres IN


(“Andres”,”Cristian”)

O se puede utilizar el operador OR

SELECT * FROM usuarios WHERE nombres=”Andrés” OR


nombres=”Cristian”

Si se desea obtener los registros cuya identificación sea menor de “130‟ y la ciudad sea
“Bogota‟, se debe utilizar el operador AND.

SELECT * FROM usuarios WHERE identificación <= ”130” AND ciudad =


”Bogota”

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 477


Si se desea obtener los registros cuyos nombres empiecen por la letra “C‟, se debe utilizar el
operador LIKE que utiliza los patrones “%‟ (todos) y “_‟ (carácter).

SELECT * FROM usuarios WHERE nombres LIKE “C%”

Si se desea obtener los registros cuyos nombres contenga la letra “i‟.

SELECT * FROM usuarios WHERE nombres LIKE “%i%”

Si se desea obtener los registros donde la segunda letra del nombre sea una “o‟.

SELECT * FROM usuarios WHERE nombres LIKE” _o%”

Si se desea obtener los registros cuya identificación este entre el intervalo 116 y 140, se debe
utilizar la cláusula BETWEEN, que sirve para especificar un intervalo de valores.

SELECT * FROM usuarios WHERE identificación BETWEEN “116” AND ”140”

1.4.2 Sentencia INSERT

La sentencia SQL de inserción de datos INSERT permite insertar información en una tabla.
Su formato es:

INSERT INTO nombre_tabla (campo1, campo2,….) VALUES (valor1,


valor2,….)

Para insertar un nuevo registro a la tabla usuarios se debería realizar la siguiente sentencia:

INSERT INTO usuarios (identificación, nombres, apellidos, dirección, teléfono,


ciudad_nac,fecha_nac) VALUES (“160”,”Carmen”,”Bolivar”,”Calle 100 # 115-
55”,”201420”,”Barranquilla”,”18/11/1692”)

1.4.3 Sentencia DELETE

La sentencia SQL de eliminación de datos DELETE permite borrar todos o un grupo


especifico de registros de una tabla. Su formato es:
DELETE FROM nombre_tabla

A continuación se realizarán algunos ejemplos:


Para eliminar todos los registros de la tabla usuarios.

DELETE FROM usuarios

Para eliminar solamente los registros cuya identificación sea mayor que “150‟.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 478


DELETE FROM usuarios WHERE identificación >”150”

Para eliminar los registros diferentes del nombre “Cristian”

DELETE FROM usuarios WHERE nombres NOT IN (“Cristian”)

1.4.4 Sentencia ALTER

La sentencia SQL ALTER permite insertar un nuevo campo en una tabla. Su formato es:
ALTER TABLE nombre_tabla ADD nombre_campo tipo_de_dato()

Para insertar un nuevo campo a la tabla usuarios llamado de tipo numérico se debería
realizar la siguiente sentencia:
ALTER TABLE usuarios ADD creditonumeric(18,0)

7.4.5 Sentencia UPDATE

La sentencia SQL de actualización UPDATE permite actualizar un campo de una tabla. Su


formato es:
UPDATE nombre_tabla SET nombre_campo=criterio

A continuación realizaremos algunos ejemplos:


Para actualizar el campo crédito con un valor de 100000 en la tabla usuarios.

UPDATE usuarios SET credito=100000

Para actualizar el campo credito en 200000 para los registros cuyo nombre empiecen por
”A‟.
UPDATE usuarios SET credito=credito +200000 WHERE nombres LIKE “A%”

Para actualizar el campo credito en 50000 para los registros cuya ciudad sea igual a “Bogota‟.

UPDATE usuarios SET credito=credito+50000 WHERE ciudad=”Bogota”

1.6. Acercándonos a ADO.NET

En este módulo, aprenderemos a trabajar con datos y fuentes de datos en Visual Basic
ADO.NET es la tecnología principal para conectarse a una base de datos, nos ofrece un
alto nivel de abstracción, ocultando los detalles de bajo nivel de la implementación de la
base de datos de un fabricante.

En este tutorial, encontrará las cosas más importantes que debe saber, para trabajar con
fuentes de datos con Visual Basic. De esta manera, aprenderá en poco tiempo, a

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 479


encontrarse cómodo en el entorno de clases de ADO.NET y podrá así, sacar el máximo
provecho a sus desarrollos. Las partes que forman parte de este módulo son las
siguientes:

ADO.NET ha sufrido a lo largo de los últimos años diferentes mejoras y actualizaciones,


desde que .NET apareció.El resumen de las diferentes versiones de ADO.NET podría quedar
de la siguiente forma.

ADO.NET 1.0 apareció con Microsoft .NET Framework 1.0. Posteriormente, ADO.NET 1.1
sufrió una pequeñas y casi inapreciables actualizaciones con la aparición de Microsoft .NET
Framework 1.1. En el caso del entorno Visual Studio, éste trabaja con Microsoft .NET
Framework 2.0 y por lo tanto, utiliza ADO.NET 2.0, el cuál añade algunas características
nuevas adicionales.
En nuestro caso, nos centraremos única y exclusivamente en ADO.NET como modelo de
objetos de acceso a datos para la plataforma .NET de Microsoft, ya que es el mismo para
cualquier tipo de versión de ADO.NET.

¿Qué es ADO.NET?

ADO.NET es la tecnología principal para conectarse aun gestor de bases de datos, con un
alto nivel de abstracción, lo que nos permite olvidarnos de los detalles de bajo nivel de las
bases de datos. Además ADO.NET es una tecnología inter operativa. Aparte del
almacenamiento y recuperación de datos, ADO.NET introduce la posibilidad de integrarse
con el estándar XML, los datos pueden 'Serializarse' directamente a y desde XML lo que
favorece el intercambio de información.

ADO.NET proporciona diferentes clases del nombre de espacio System.Data dentro de las
cuáles, destacaremos por encima de todas, la clase DataView, la clase DataSet y la clase
DataTable.

Este conjunto de clases de carácter armónico, funcionan de igual forma con la capa inferior
que es la que corresponde a los proveedores de acceso a datos con los que podemos trabajar.
Esto facilita el trabajo en n-capas y la posible migración de aplicaciones que utilicen una
determinada fuente de datos y deseemos en un momento dado, hacer uso de otra fuente de
datos.

¿Qué capas o qué partes hay dentro de ADO.NET?

Dentro de ADO.NET tenemos dos partes importantes.


La primera de ellas es la que corresponde con el nombre de espacio System.Data y que
constituye los objetos y clases globales de ADO.NET.

La otra parte es la que corresponde con los objetos que permiten el acceso a datos a una
determinada fuente de datos desde ADO.NET y que utilizan así mismo, las clases del nombre
de espacio System.Data.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 480


Esta última parte, queda constituida por las clases y objetos de los diferentes proveedores
de acceso a datos como se muestra en la figura 1.

Visión general de las clases de ADO.NET

Para resumir de alguna forma lo que estamos comentando, diremos que el trabajo de
conexión con la base de datos, la ejecución de una instrucción SQL determinada, una vista,
etc., la realiza el proveedor de acceso a datos.

Recuperar esos datos para tratarlos, manipularlos o volcarlos a un determinado control o


dispositivo, es acción de la capa superior que corresponde con el nombre de espacio
System.Data.

A continuación veremos todo esto con más detalle y comprenderemos de una forma más
clara cada una de las partes que componen el modelo de trabajo con ADO.NET.

¿Qué nos permite realmente ADO.NET cuando trabajamos con XML?

El entorno de Microsoft .NET Framework nos proporciona el trabajo con estándares y con
ello, la posibilidad de trabajar con diferentes tipos de aplicaciones, entornos, sistemas
operativos y lenguajes sin necesidad de conocer lo que hay al otro lado de nuestra
aplicación.

XML es sin lugar a dudas, el lenguaje de etiquetas por excelencia, válido para llevar a cabo
esta tarea sin tener un impacto relevante cuando trabajamos con diferentes soluciones en
entornos dispares.
Tanto la posibilidad de trabajar con Servicios Web XML como con documentos e
información en XML, sobre todo al trabajar con fuentes de datos en ADO.NET, nos
proporciona a los desarrolladores las posibilidades necesarias que nos permite hacer que
la información con la que trabajamos, pueda ser tratada entre diferentes sistemas o
entornos, sin que por ello nos preocupemos de lo que hay al otro lado.

1.7. System.Data

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 481


Las clases del nombre de espacio System.Data son bastantes extensas y variadas. Quizás las
clases más importantes son la clase DataView, la clase DataSet y la clase DataTable.

La clase DataSet
El DataSet es una representación de datos residente en memoria que proporciona una
modelo de programación relacional coherente independientemente del origen de datos que
contiene. El DataSet contiene en sí, un conjunto de datos que han sido volcados desde el
proveedor de datos.
Debemos tener en cuenta que cuando trabajamos con DataSets, el origen de datos no es lo
más importante, ya que éste, puede ser cualquier tipo de origen de datos. No tiene porqué
ser una base de datos.
Un DataSet contiene colecciones de DataTables y DataRelations.
El DataTable contiene una tabla o tablas, mientras que la DataRelation contiene las
relaciones entre las DataTables. Sin embargo, no es necesario especificar todo esto hasta
el último detalle como veremos más adelante.

La clase DataView
Este objeto nos permite crear múltiples vistas de nuestros datos, además de permitirnos
presentar los datos. Es la clase que nos permite representar los datos de la clase DataTable,
permitiéndonos editar, ordenar y filtrar, buscar y navegar por un conjunto de datos
determinado.

La clase DataTable
Este objeto nos permite representar una determinada tabla en memoria, de modo que
podamos interactuar con ella.
A la hora de trabajar con este objeto, debemos tener en cuenta el nombre con el cuál
definamos una determinada tabla, ya que los objetos declarados en el DataTable es sensitivo
a mayúsculas y minúsculas.

Un pequeño ejemplo práctico


El siguiente ejemplo práctico, nos enseña a utilizar un DataSet y nos muestra cómo
podemos acceder a los objetos que dependen de un DataSet para recuperar por ejemplo,
los campos y propiedades de una determinada tabla o tablas.

Imports System.Data
Imports System.Data.SqlClient
Imports System.Xml
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles MyBase.Load
Dim Conexion As String =

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 482


"server=.;uid=sa;password=VisualBasic;database=MSDNVideo"
Dim MiTabla As DataTable
Dim MiColumna As DataColumn
Dim MiDataSet As New DataSet()
Dim Comando As New SqlDataAdapter("SELECT * FROM
ALQUILERES", Conexion)
Comando.Fill(MiDataSet, "ALQUILERES")
' Recorremos las tablas
For Each MiTabla In MiDataSet.Tables
TextBox1.Text += "Tabla: " & MiTabla.TableName & vbCrLf
' Recorremos las Columnas de cada Tabla
For Each MiColumna In MiTabla.Columns
TextBox1.Text += MiColumna.ColumnName & vbTab &
"(" & MiColumna.DataType.Name & ")" & & vbCrLf
Next
Next
Comando = Nothing
End Sub
End Class

Nuestro ejemplo en ejecución es el que se muestra en la figura 1.

Ejemplo en ejecución del uso de DataSet, DataTable y DataColumn

1.8. Los proveedores de acceso a datos


Los proveedores de acceso a datos es la capa inferior de la parte correspondiente al
acceso de datos y es la responsable de establecer la comunicación con las fuentes de
datos. En este conjunto de nombres de espacio, encontraremos casi siempre las clases
Connection, Command, DataAdapter y DataReader como las clases más generales, las
cuales nos permiten establecer la conexión con la fuente de datos.

Proveedores de acceso a datos de .NET Framework

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 483


Dentro del entorno .NET Framework, encontramos un nutrido conjunto de
proveedores de acceso a datos. Estos son los siguientes:
● ODBC .NET Data Provider
● OLE DB .NET Data Provider
● Oracle Client .NET Data Provider
● SQL Server .NET Data Provider

Estos proveedores de acceso a datos incluidos en Microsoft .NET Framework, los


podemos encontrar en los nombres de espacio:
● System.Data.Odbc
● System.Data.OleDb
● System.Data.OracleClient
● System.Data.SqlClient
El proveedor ODBC .NET permite conectar nuestras aplicaciones a fuentes de datos a
través de ODBC.
El proveedor OLE DB .NET permite conectar nuestras aplicaciones a fuentes de datos a
través de OLE DB.

El proveedor Oracle Client .NET es un proveedor de acceso a datos especialmente


diseñado para bases de datos Oracle.
Por último, el proveedor SQL Server .NET es un proveedor de acceso a datos nativo, que
nos permite conectar nuestras aplicaciones a fuentes de datos Microsoft SQL Server 7 o
posterior. Se trata de un proveedor específico para bases de datos Microsoft SQL Server
7.0, Microsoft SQL Server 2000 y Microsoft SQL Server 2005; 2008

Nota:
Siempre que pueda, utilice para acceder a fuentes de datos, un proveedor de
acceso a datos nativo. Esto le permitirá aumentar considerablemente el
rendimiento a la hora de establecer la conexión con una determinada fuente de
datos

Los proveedores de acceso a datos que distribuye Microsoft en ADO.NET y algunos


desarrollados por otras empresas o terceros, contienen los mismos objetos, aunque los
nombres de éstos, sus propiedades y métodos, pueden ser diferentes.

Más adelante veremos algún ejemplo, y observará en la práctica cuáles son estas diferencias
más destacables.

Otros proveedores de acceso a datos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 484


Si bien el proveedor de acceso a datos es el mecanismo a través del cuál podemos establecer
una comunicación nativa con una determinada fuente de datos, y dado que Microsoft
proporciona los proveedores de acceso a datos más corrientes, es cierto que no los
proporciona todos, si bien, con OLE DB y ODBC, podemos acceder a la inmensa totalidad
de ellos.
Sin embargo, hay muchos motores de bases de datos de igual importancia como Oracle,
MySql, AS/400, etc. En estos casos, si queremos utilizar un proveedor de acceso a datos
nativo, deberemos acudir al fabricante o a empresas o iniciativas particulares para que nos
proporcionen el conjunto de clases necesarias que nos permitan abordar esta acción.

El objeto Connection
Este objeto es el encargado de establecer una conexión física con una base de datos
determinada. Para establecer la conexión con una determinada fuente de datos, no sólo
debemos establecer la cadena de conexión correctamente, sino que además deberemos
usar los parámetros de conexión y el proveedor de acceso a datos adecuado. Con este
objeto, podremos además abrir y cerrar una conexión.

El objeto Command
Este objeto es el que representa una determinada sentencia SQL o un Stored
Procedure. Aunque no es obligatorio su uso, en caso de necesitarlo, lo utilizaremos
conjuntamente con el objeto DataAdapter que es el encargado de ejecutar la instrucción
indicada.

El objeto DataAdapter
Este objeto es quizás el objeto más complejo y a la vez complicado de todos los que
forman parte de un proveedor de acceso a datos en .NET. Cuando deseamos establecer
una comunicación entre una fuente de datos y un DataSet, utilizamos como intermediario
a un objeto DataAdapter. A su vez, un DataAdapter contiene 4 objetos que debemos
conocer:
● SelectCommand es el objeto encargado de realizar los trabajos de selección de
datos con una fuente de datos dada. En sí, es el que se encarga de devolver y rellenar
los datos de una fuente deb datos a un DataSet.
● DeleteCommand es el objeto encargado de realizar las acciones de borrado de
datos.
● InsertCommand es el objeto encargado de realizar las acciones de inserción de
datos.
● UpdateCommand es el objeto encargado de realizar las acciones de
actualización de datos.

Los objetos DeleteCommand, InsertCommand y UpdateCommand son los objetos que se


utilizan para manipular y transmitir datos de una fuente de datos determinada, al contrario
del objeto SelectCommand que tan sólo interactúa con la fuente de datos para recuperar una

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 485


porción o todos los datos indicados en el objeto Command anteriormente comentado.

El objeto DataReader
Este objeto es el utilizado en una sola dirección de datos. Se trata de un objeto de acceso a
datos muy rápido. Este objeto puede usar a su vez el objeto Command o el método
ExecuteReader.

1.9.- El concepto DataBinding

DataBinding es una expresión de enlace a datos. Como veremos a continuación es una forma
rápida y sencilla de manejar la fuentes de datos mediante su enlace con controles o clases.

El uso de DataBind
El método DataBind se utiliza para rellenar de datos un determinado control o clase.
Muchos controles y clases, posee este método al que le asignaremos un conjunto de datos
para que se rellene con ellos, pudiendo después interactuar con los datos de forma directa.
En sí, un DataBinding es un enlace a datos que se encarga de rellenar de datos a un
determinado control o clase. Como ejemplo de esto, veremos como rellenar un control
TextBox con un dato utilizando este método.
Iniciaremos una nueva aplicación Windows y escribiremos el siguiente código fuente:

Imports System.Data
Imports System.Data.SqlClient
Imports System.Xml
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim Conexion As String =
"server=.;uid=sa;password=VisualBasic;database=MSDNVideo"
Dim MiDataSet As New DataSet()
Dim Comando As New SqlDataAdapter("SELECT TITULO FROM
ALQUILERES, PELICULAS WHERE PELICULACODBARRAS = CODBARRAS
AND SOCIONIF = '111111'", Conexion)
' Rellenamos el DataSet con el contenido de la sentencia SELECT
Comando.Fill(MiDataSet, "PELIS")
' Rellenamos el control TextBox1 con el dato correspondiente a la primera fila
' de la sentencia SELECT ejecutada
TextBox1.DataBindings.Add("Text", MiDataSet,"PELIS.TITULO")
Comando = Nothing
End Sub
End Class

Nuestro ejemplo en ejecución es el que se muestra en la figura.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 486


Ejemplo en ejecución del uso de DataBinding

1.10.- Otras consideraciones

Dentro de las conexiones a fuentes de datos, hay algunas partes de éstas que permanecen a
veces en el olvido y su importancia sin embargo, es bastante grande. La acción más pesada
cuando realizamos un acceso a una fuente de datos, se encuentra en la conexión con la fuente
de datos. Esa tarea, simple tarea, es la que más recursos del sistema consume cuando
Accedemos a fuentes de datos.

Esto lo debemos tener en cuenta, y por lo tanto, variante de esto que comentamos son
las siguientes premisas:
● La conexión debe realizarse siempre que se pueda, con los proveedores de acceso a
datos nativos, que por lo general salvo raras excepciones, serán más rápidos que los accesos
a fuentes de datos a través de proveedores del tipo OLE DB y ODBC.
● La conexión con la fuente de datos (apertura de la conexión), debe realizarse lo más
tarde posible. Es recomendable definir todas las variables que podamos, antes de realizar
la conexión.
● La conexión debe cerrarse lo antes posible, siempre y cuando no tengamos la necesidad
de utilizar la conexión previamente abierta.

Hay más particularidades a tener en cuenta cuando trabajamos con fuentes de datos. El
hecho de que con un DataSet podamos trabajar con datos desconectados, no significa que
dentro de él, podamos abrir una tabla con una cantidad de registros enormes, y trabajemos
sobre ella creyendo que esto nos beneficiará. Todo lo contrario.

1.11.- El paradigma de la conexión

Cuando abordamos un proyecto de acceso a fuentes de datos, siempre nos


encontramos con una duda existencial.

¿Debemos crear una conexión con la base de datos al principio de nuestra aplicación y

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 487


cerrarla cuando la aplicación se cierre?, ¿o debemos crear una conexión con la base de
datos sólo cuando vayamos a trabajar con la fuente de datos?. ¿Y si estamos trabajando
continuamente con una fuente de datos?, ¿cómo penalizarían todas estas acciones?.
Es difícil de asumir que acción tomar en cada caso, y es que dependiendo de lo que vayamos
a realizar, a veces es más efectiva una acción que otra, y en otras ocasiones, no está del todo
claro, ya que no existe en sí una regla clara que especifique qué acción tomar en un momento
dado.
Lo que sí está claro es que el modelo de datos de ADO.NET que hemos visto, quedaría
resumido en cuanto a la conectividad de la manera en la que se representa en la figura

Visión general de ADO.NET respecto a la conectividad con bases de datos

El objeto DataSet nos ofrece la posibilidad de almacenar datos, tablas y bases de datos de
una determinada fuente de datos. De esta manera, podemos trabajar con las aplicaciones
estando desconectados de la fuente de datos.
Sin embargo, a veces necesitamos trabajar con la fuente de datos estando conectados a ella.
El objeto DataReader nos ofrece precisamente la posibilidad de trabajar con fuentes de
datos conectadas.

Por otro lado, el objeto DataReader tiene algunas particularidades que conviene
conocer y que veremos a continuación.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 488


2.- Trabajando con datos

2.1.- Conociendo el objeto DataReader

El objeto DataReader nos permite como hemos indicado anteriormente, establecer una
conexión con una fuente de datos y trabajar con esta fuente de datos sin desconectarnos
de ella, sin embargo, hay diferentes cualidades y particularidades que conviene
conocer.

DataReader es de solo lectura


Lo que hemos dicho anteriormente, requiere sin embargo, que esta conexión se
establezca en un modo de sólo lectura, al contrario de lo que se puede hacer con el
objeto DataSet, con el que podemos interactuar con la fuente de datos en modo lectura
y modo escritura.

DataReader se maneja en una sola dirección


El objeto DataReader sólo permite que nos desplacemos por los datos en una sola dirección,
sin vuelta atrás. Por el contrario, el objeto DataSet nos permite movernos por los registros
para adelante y para atrás.
Además, sólo podemos utilizar el objeto DataReader con conexiones establecidas en una
sentencia SQL por ejemplo, pero no podemos variar esta. Para hacerlo, debemos entonces
modificar la conexión con el comando establecido.

DataReader es rápido
Debido a su naturaleza y características, este objeto es bastante rápido a la hora de
trabajar con datos. Como es lógico, consume además menos memoria y recursos que un
objeto DataSet por ejemplo. Sin embargo, dependiendo de las necesidades con las que
nos encontremos, puede que este método de acceso y trabajo no sea el más idóneo.

Analizando el flujo de trabajo de DataReader


Cuando trabajamos con fuentes de datos conectadas, trabajaremos con el objeto
DataReader.

Para trabajar con este objeto, utilizaremos los objetos siguientes del proveedor de
acceso a datos:
● Connection
● Command
● DataReader

Un resumen gráfico de esto es lo que podemos ver en la figura 1.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 489


El flujo de conectividad de DataReader

2.2.- Un primer contacto con el objeto DataReader

A continuación veremos un ejemplo sencillo sobre la forma de trabajar con DataReader

Un ejemplo simple para entenderlo mejor


Tenga en cuenta que en el siguiente ejemplo nos conectaremos a Microsoft SQL
Server y recorreremos los registros uno a uno en un ambiente conectado y
volcaremos estos registros en un control TextBox.

Imports System.Data
Imports System.Data.SqlClient
Imports System.Xml

Public Class Form1


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles MyBase.Load
Dim Conexion As String =
"server=.;uid=sa;password=VisualBasic;database=MSDNVideo"
Dim MiConexion As New SqlConnection(Conexion)
Dim MiDataReader As SqlDataReader
Dim Comando As New SqlCommand("SELECT TITULO FROM
ALQUILERES, PELICULAS WHERE PELICULACODBARRAS = CODBARRAS
AND
SOCIONIF = '111111'", MiConexion)
MiConexion.Open()
MiDataReader = Comando.ExecuteReader()
While MiDataReader.Read()
TextBox1.Text += MiDataReader("TITULO") & vbCrLf
End While
Comando = Nothing

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 490


MiConexion.Close()
End Sub
End Class

El código de ejemplo en ejecución es el que se muestra en la figura 1.

Ejemplo en ejecución del uso simple de DataReader

Este es un ejemplo simple del uso de DataReader.


Sin embargo, el objeto DataReader contiene un conjunto de propiedades y métodos que nos
proporcionan acciones determinadas. Por ejemplo, en el ejemplo anterior, hemos dado por
hecho que la ejecución de la instrucción Select nos devolverá uno o más valores, pero
podríamos también saber antes de manipular y trabajar con los posibles datos, si hay o no
información. Esto lo conseguimos con el método HasRows.

2.3.- ¿Trabaja DataReader en un ambiente conectado


Realmente?

Pese a todo esto, ¿que ocurre si trabajando en un ambiente conectado se desconecta el


servidor de acceso a datos?. Imaginemos por un instante, que la conexión con SQL Server
se establece correctamente y que en un momento dado se detiene el servicio del servidor
de base de datos. Esto es lo que veremos en el siguiente ejemplo.

Desenchufando la fuente de datos usando DataReader

Inicie un nuevo proyecto, inserte en el formulario de la aplicación un control TextBox y un


control Button, y escriba el código que se detalla a continuación:

Imports System.Data
Imports System.Data.SqlClient
Imports System.Xml
Public Class Form1
Private Conexion As String =

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 491


"server=.;uid=sa;password=VisualBasic;database=MSDNVideo"
Private strSQL As String = "SELECT TITULO FROM ALQUILERES,
PELICULAS WHERE PELICULACODBARRAS = CODBARRAS AND SOCIONIF
= '111111'"
Private MiConexion As New SqlConnection(Conexion)
Private MiDataReader As SqlDataReader
Private Contador As Long = 0
Private Posicion As Long = 0
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles MyBase.Load
' Establecemos la Conexión con la base de datos
Establecer_Conexion(True)
' Si hay datos los mostramos, sino deshabilitamos la opción (botón) para recorrerlos
If Not MiDataReader.HasRows Then
Button1.Enabled = False
Else
Button1_Click(sender, e)
End If
End Sub

Private Sub Establecer_Conexion(ByVal bolAccion As Boolean)


Dim Comando As SqlCommand
If bolAccion Then
' True => Establecemos la conexión
Comando = New SqlCommand(strSQL, MiConexion)
' Abrimos la Conexión
MiConexion.Open()
' Ejecutamos la sentencia SQL
MiDataReader = Comando.ExecuteReader()
' Obtenemos la cantidad de registros obtenidos
Contador = MiDataReader.VisibleFieldCount() + 1
Else
' False => Finalizamos la conexión
Button1.Enabled = False
' Cerramos la Conexión
Comando = Nothing
MiConexion.Close()
End If
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles Button1.Click
' Recorremos los registros y los mostramos
Posicion += 1
MiDataReader.Read()
TextBox1.Text = MiDataReader("TITULO")

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 492


' Si hemos recorrido el objeto por completo, finalizamos la Conexión y
' deshabilitamos el control Button que nos permite recuperar los registros
If Posicion = Contador Then
Establecer_Conexion(False)
End If
End Sub
End Class

Suponiendo que tenemos en nuestra base de datos varios registros, ejecute la aplicación. Si
todo ha ido como se esperaba, observaremos que nuestra aplicación tiene un aspecto como
el que se muestra en la figura

Ejemplo en ejecución del uso de DataReader en un ambiente conectado,


forzando la desconexión de la fuente de datos

En este punto, detenga el servicio de SQL Server y pulse el botón Siguiente >>. Observará
que la aplicación sigue funcionando. En este punto se hará la pregunta que todos nos hemos
hecho, ¿no es el objeto DataReader un objeto conectado?, ¿cómo es posible que funcione si
hemos detenido el servicio de SQL Server?. La respuesta es sencilla. El objeto DataReader
recupera un nutrido conjunto de valores llenando un pequeño buffer de datos e información.

Si el número de registros que hay en el buffer se acaban, el objeto DataReader regresará a


la fuente de datos para recuperar más registros. Si el servicio de SQL Server está detenido
en ese momento o en su caso, la fuente de datos está parada, la aplicación generará un error
a la hora de leer el siguiente registro.
En sí, DataReader es un objeto conectado, pero trabaja en background con un conjunto de
datos, por lo que a veces nos puede resultar chocante su comportamiento como el ejemplo
que comento.

2.4.- Usando DataSource con DataReader

¿Podemos usar el método DataSource con el objeto DataReader?.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 493


Demostración del uso de DataSource con DataReader
La respuesta es sí, en ADO.NET 2.0, se ha incorporado un nuevo método al objeto
DataTable que le permite tener mayor independencia respecto al modo en el que nos
conectemos y recuperemos datos de una fuente de datos. Recuerde que podemos
recuperar datos en modo conectado DataReader o en modo desconectado DataSet.

Este método que se ha incorporado a ADO.NET y que tiene por nombre Load, nos permite
cargar un DataReader para volcarlo a continuación dentro de un control como por ejemplo
el control DataGridView. Lo mejor es que veamos como funciona esto con un ejemplo que
nos ayude a comprender mejor la teoría. Inserte en un formulario un control DataGridView
y escriba el siguiente código:

Imports System.Data
Imports System.Data.SqlClient
Imports System.Xml
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
' Declaramos las variables a utilizar
Dim Conexion As String =
"server=.;uid=sa;password=VisualBasic;database=MSDNVideo"
Dim strSQL As String = "SELECT TITULO FROM ALQUILERES,
PELICULAS WHERE PELICULACODBARRAS = CODBARRAS AND SOCIONIF
= '111111'"

Dim MiConexion As New SqlConnection(Conexion)


Dim MiDataReader As SqlDataReader
Dim MiDataTable As New DataTable
Dim Comando As SqlCommand
' Establecemos la Conexión con la base de datos
Comando = New SqlCommand(strSQL, MiConexion)
' Abrimos la Conexión
MiConexion.Open()
' Ejecutamos la sentencia SQL
MiDataReader = Comando.ExecuteReader()
' Cargamos los resultados en el objeto DataTable
MiDataTable.Load(MiDataReader, LoadOption.OverwriteChanges)
' Volcamos los datos en el control DataGridView
DataGridView1.DataSource = MiDataTable
' Cerramos la Conexión
Comando = Nothing
MiConexion.Close()
End Sub
End Class

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 494


Nuestro ejemplo en ejecución es el que podemos ver en la figura

Ejemplo en ejecución del uso de DataReader y DataSource en un control


DataGridView

Con todo y con esto, lo que realmente es curioso, es que hemos olvidado por un instante que
el objeto DataReader es un objeto de sólo lectura que funciona en una única dirección, hacia
delante. ¿Qué significa esto o como puede influir o como podemos aprovechar esta
circunstancia en nuestros desarrollos?.

Carga segmentada de datos con DataSource y DataReader


Si recuperamos los datos de una fuente de datos con DataReader y leemos algunos de sus
datos y posteriormente, ejecutamos el método DataSource, el resto de datos, aquellos datos
que quedan en el DataReader, serán los que se vuelquen en el control que definamos como
destino de los datos. Imaginemos el ejemplo anterior, y el siguiente código fuente.

Imports System.Data
Imports System.Data.SqlClient
Imports System.Xml
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
' Declaramos las variables a utilizar
Dim Conexion As String =
"server=.;uid=sa;password=VisualBasic;database=MSDNVideo"

Dim strSQL As String = "SELECT TITULO FROM ALQUILERES,


PELICULAS WHERE PELICULACODBARRAS = CODBARRAS AND SOCIONIF
= '111111'"

Dim MiConexion As New SqlConnection(Conexion)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 495


Dim MiDataReader As SqlDataReader
Dim MiDataTable As New DataTable
Dim Comando As SqlCommand
' Establecemos la Conexión con la base de datos
Comando = New SqlCommand(strSQL, MiConexion)
' Abrimos la Conexión
MiConexion.Open()
' Ejecutamos la sentencia SQL
MiDataReader = Comando.ExecuteReader()
' Leemos el primer registro y así nos posicionamos a partir del segundo de ellos
MiDataReader.Read()
' Cargamos los resultados en el objeto DataTable
MiDataTable.Load(MiDataReader, LoadOption.OverwriteChanges)
' Volcamos los datos en el control DataGridView
DataGridView1.DataSource = MiDataTable
' Cerramos la Conexión
Comando = Nothing
MiConexion.Close()
End Sub
End Class

En este caso, lo que ocurre como ya hemos comentado, es que los datos que se cargan son
los que aún no han sido leídos en el objeto DataReader, por lo que se mostrarán todos los
datos desde el último leído hasta llegar al final del objeto.

2.5.- Usando los componentes de acceso a datos de .NET

Los componentes del entorno .NET nos proporcionan las características necesarias
para poder acceder a fuentes de datos de forma rápida y sencilla.
El mejor ejemplo de esto que comento es el que veremos a continuación.

Demostración del uso de BindingSource y BindingNavigator


Para ello, crearemos un proyecto nuevo e insertaremos un control BindingSource y un
control BindingNavigator dentro del formulario.

También insertaremos un control TextBox al formulario, dónde presentaremos la


información sobre la que navegaremos. Nuestro formulario con los controles insertados en
él, tendrá un aspecto similar al que se presenta en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 496


Controles de navegación y acceso a datos dispuestos en el formulario
Figura 1

Una vez llegado a este punto, lo que tendremos que hacer a continuación será escribir
el código fuente necesario para poder representar los datos de la sentencia SQL en el
control BingindNavigator, para que a su vez los presente en el control TextBox. A
continuación se indica el código fuente de esta parte de demostración de la aplicación.

Imports System.Data
Imports System.Data.SqlClient
Imports System.Xml
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal eAs
System.EventArgs) Handles MyBase.Load
' Declaramos las variables a utilizar
Dim Conexion As String =
"server=.;uid=sa;password=VisualBasic;database=MSDNVideo"
Dim strSQL As String = "SELECT TITULO FROM ALQUILERES,
PELICULAS WHERE PELICULACODBARRAS = CODBARRAS AND SOCIONIF
= '111111'"
Dim MiConexion As New SqlConnection(Conexion)
Dim MiDataReader As SqlDataReader
Dim MiDataTable As New DataTable
Dim Comando As SqlCommand
' Establecemos la Conexión con la base de datos
Comando = New SqlCommand(strSQL, MiConexion)
' Abrimos la Conexión
MiConexion.Open()
' Ejecutamos la sentencia SQL
MiDataReader = Comando.ExecuteReader()
' Cargamos los resultados en el objeto DataTable
MiDataTable.Load(MiDataReader, LoadOption.OverwriteChanges)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 497


' Volcamos los datos en el control TextBox
BindingSource1.DataSource = MiDataTable
BindingNavigator1.BindingSource = BindingSource1
TextBox1.DataBindings.Add(New Binding("Text", BindingSource1, "TITULO",
True))
' Cerramos la Conexión
Comando = Nothing
MiConexion.Close()
End Sub
End Class

2.6.- Esquema general de la estructura desconectada de acceso a


datos

En los capítulos anteriores de este módulo, hemos visto ya el uso de la clase DataSet. Incluso
lo hemos visto con algún ejemplo.

La clase DataSet está pensada y diseñada para trabajar con fuentes de datos
desconectadas. Indudablemente, en este punto, debemos tener clara la estructura
general de cómo funciona el acceso desconectado con fuentes de datos. En la figura,
podemos observar el diagrama general de esta parte

Estructura general del uso de DataSet en el acceso desconectado a


datos

Connection, DataAdapter y DataSet


Como podemos observar en la figura 1, para comunicarnos con una fuente de datos, siempre
deberemos establecer una conexión, independientemente de si la conexión con la fuente de
datos va a permanecer a lo largo del tiempo o no.
El objeto Connection nos permite por lo tanto, establecer la conexión con la fuente de datos.
El objeto DataSet nos permite por otro lado, recoger los datos de la fuente de datos y
mandárselos a la aplicación.

Entre medias de estos dos objetos, encontramos el objeto DataAdapter que hace las

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 498


funciones de puente o nexo de unión entre la conexión y el objeto DataSet.
Esto es lo que veremos a continuación, como funciona el objeto DataAdapter, y como encaja
todo esto en el acceso a fuentes de datos desconectadas.

2.6.1- Conociendo el objeto DataAdapter

El objeto DataAdapter forma parte del proveedor de acceso a datos, tal y como se muestra
en la figura

Visión general de las clases de ADO.NET

Cada proveedor de acceso a datos posee su propio objeto DataAdapter. Cuando realizamos
alguna modificación o acción sobre la fuente de datos, utilizaremos siempre el objeto
DataAdapter a caballo entre el objeto DataSet y la fuente de datos establecida a través de
la conexión con el objeto Connection.Con el objeto DataAdapter, podremos además realizar
diferentes acciones sobre nuestras bases de datos, acciones como la ejecución general de
sentencias de SQL no sólo para seleccionar un conjunto de datos, sino para alterar el
contenido de una base de datos o de sus tablas.

Connection, DataAdapter y DataSet


Antes de entrar en materia más profundamente, diremos que en lo que respecta a los
proveedores de acceso a datos que vienen integrados con .NET, encontramos dos formas de
usar un DataAdapter.

La primera de ellas es utilizando los componentes del proveedor de acceso a datos. La


segunda de ellas es utilizando las clases del nombre de espacio del proveedor de acceso a
datos. La mejor forma de entender todo esto que comentamos, es trabajando con un ejemplo
práctico que nos enseñe a usar el objeto DataAdapter en Visual Studio

Utilizando las clases de .NET


En este primer ejemplo de demostración del uso de DataAdapter a través de código
usando para ello las clases de .NET, estableceremos una conexión con SQL Server y

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 499


mostraremos los datos recogidos en un control TextBox.
Iniciaremos Visual Studio y seleccionaremos un proyecto de formulario de Windows.
Dentro del formulario, insertaremos un control TextBox y añadiremos dos referencias al
proyecto. Las referencias añadidas serán a las librerías System.Data y System.XML,
como se muestra en la figura

Referencias a las clases de acceso a datos de .NET

Una vez que hemos añadido las referencias necesarias para utilizar las clases que queremos
en nuestro proyecto, iremos al código y escribiremos las siguientes instrucciones:

Imports System.Data
Imports System.Data.SqlClient
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
' Establecemos la cadena de conexión con la BBDD
Dim Conexion As String =
"server=.;uid=sa;password=VisualBasic;database=MSDNVideo"
' Declaramos el DataSet dónde volcaremos los datos
Dim MiDataSet As New DataSet()
' Declaramos el DataAdapter estableciendo
' la conexión con la fuente de datos SQL
Dim Comando As New SqlDataAdapter("SELECT SocioNIF,
FechaAlquiler FROM ALQUILERES", Conexion)

' Rellenamos el DataSet con el contenido de la instrucción

Comando.Fill(MiDataSet)
' Cerramos la conexión con la BBDD

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 500


Comando = Nothing
' Declaramos la propiedad Row para recorrer
' las filas contenidas en el DataSet
Dim Row
' Recorremos todas las filas y las tratamos
For Each Row In MiDataSet.Tables(0).Rows
TextBox1.Text += Row("SocioNIF").ToString & vbTab &
Row("FechaAlquiler") & vbCrLf
Next
' Vaciamos el DataSet para liberar memoria
MiDataSet = Nothing
End Sub
End Class

El ejemplo en ejecución del uso de DataAdapter junto con las clases de .NET es el que se
muestra en la figura

Ejemplo del acceso a datos con DataAdapter a través de las clases de .NET

2.7.- Utilizando los componentes de .NET


Existe otro método de acceso a fuentes de datos diferente a las clases de .NET, el acceso a
través de componentes que nos faciliten esa tarea. Sin embargo, los componentes de acceso
a datos, utilizan por detrás las clases de .NET que hemos visto, lo que ocurre, es que
simplifica enormemente el trabajo y ahorra tiempo a la hora de desarrollar aplicaciones.
De todos los modos, todo depende de la utilidad o necesidades con las que nos encontremos
en un momento dado. Iniciaremos un proyecto Windows nuevamente, e insertaremos en él
un control TextBox.

A continuación, añadiremos los componentes de acceso a fuentes de datos SQL Server que
es la fuente de datos origen. Como hemos visto, para conectar a fuentes de datos SQL Server,
hemos utilizado el nombre de espacio System.Data y hemos importado en el proyecto los
nombres de espacio System.Data y System.Data.SqlClient.

Los componentes .NET de acceso a fuentes de datos de SQL Server, se identifican por el
nombre Sqlxxx, siendo xxx el tipo de componente a utilizar. Para poder utilizarlos,

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 501


deberemos añadirlo a la barra de herramientas.

Para añadir los componentes a nuestro proyecto, haremos soble clic sobre el formulario y
posteriormente haremos clic con el botón secundario del mouse sobre la barra de
herramientas y seleccionaremos la opción Elegir elementos... como se muestra en la figura

Opción de la barra de herramientas para añadir componentes al entorno

Una vez que hemos hecho esto, seleccionaremos los componentes SqlCommand,
SqlCommandBuilder, SqlConnection, SqlDataAdapter y SqlDataSource, tal y como se
muestra en la figura

Componentes a añadir al entorno

Una vez que hemos añadido los componentes al entorno, estos quedarán dispuestos
dentro de la barra de herramientas como se indica en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 502


Componentes añadidos en la barra de herramientas

Lo primero que haremos será insertar un componente SqlConnection dentro del


formulario. Acudiremos a la ventana de propiedades del componente y
modificaremos la propiedad ConnectionString dentro de la cuál escribiremos la
instrucción:

server=.;uid=sa;password=VisualBasic;database=MSDNVideo

Entendiendo que ésta, es la cadena de conexión válida con nuestra base de datos. A
continuación añadiremos el componente SqlDataAdapter a nuestro formulario. Si se abre
alguna ventana, ciérrela.

Vamos a configurar el control con la ventana Propiedades. Podríamos haberlo hecho


desde el asistente que se nos ha abierto, pero lo vamos a hacer de otra forma menos
sencilla.
Sitúese sobre la propiedad SelectCommand, y dentro de ésta, en la propiedad Connection.
Lo que vamos a hacer, es asignar al componente SqlDataAdapter el componente de conexión
que vamos a usar para establecer la comunicación entre la fuente de datos y nuestra
aplicación.

Despliegue la propiedad Connection indicada, y seleccione el componente de conexión


SqlConnection1 anteriormente configurado, tal y como se muestra en la figura.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 503


Componente SqlDataAdapter con la conexión establecida para ser
usada en la ejecución de nuestra aplicación

Por último, inserte un componente DataSet al formulario. Todos los componentes


quedarán por lo tanto insertados, tal y como se indica en la figura

Componentes añadidos en el formulario de nuestra aplicación


Una vez que tenemos todo preparado, tan sólo nos queda escribir la parte de código fuente
necesario para poder realizar todas las operaciones y acciones que necesitamos. A
continuación, se expone el código fuente de nuestra aplicación de demostración:

Public Class Form1

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 504


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
' Establecemos la cadena SQL a utilizar
SqlDataAdapter1.SelectCommand.CommandText = "SELECT
SocioNIF, FechaAlquiler FROM ALQUILERES"
' Abrimos la Conexión
SqlConnection1.Open()

' Rellenamos el DataSet con el contenido de la instrucción SQL


SqlDataAdapter1.Fill(DataSet1)
' Cerramos la Conexión
SqlConnection1.Close()
' Declaramos la propiedad Row para recorrer las filas contenidas en el DataSet
Dim Row
' Recorremos todas las filas y las tratamos
For Each Row In DataSet1.Tables(0).Rows
TextBox1.Text += Row("SocioNIF").ToString & vbTab & Row("FechaAlquiler") &
vbCrLf
Next
End Sub
End Class

Ahora nos queda únicamente ejecutar nuestra aplicación para estudiar el resultado final.
Este es el que se puede ver en la figura

Ejemplo en ejecución del uso de componentes

Pese a todo lo que hemos visto, quizás se pregunte como es que en el caso del primer ejemplo
que hemos visto y en el que hemos declarado el uso de un DataAdapter sin usar componentes,
hemos tenido la obligatoriedad de añadir las referencias a los nombres de espacio
System.Data y System.Xml, mientras que en este segundo ejemplo, no hemos hecho
referencia a ellos.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 505


En realidad nosotros no hemos hecho referencia a ellos, pero al insertar los componentes
dentro del formulario, el entorno Visual Studio 2005 se ha encargado por nosotros de añadir
esas referencias al proyecto, tal y como puede verse en la figura.

Referencias añadidas automáticamente al trabajar con componentes de acceso a datos

2.7.1.- Insertando datos a través del objeto DataAdapter

Hasta ahora, todos los ejemplos que hemos visto del objeto DataAdapter, han sido ejemplos
del uso de selección de datos, pero aún no hemos visto como debemos trabajar cuando
realicemos otras acciones sobre la fuente de datos.
A continuación, veremos como realizar acciones de actualización de datos, utilizando
para ello el objeto DataAdapter.

Nota:
El DataSet permanece desconectado de la fuente de datos y si realizamos una
modificación o alteración de los datos de un DataSet, estos no son propagados a la
fuente de datos. Para ello, el DataAdapter debe recibir la orden que queramos
ejecutar.

Agregando datos con el objeto DataAdapter


Suponiendo que hemos recogido un conjunto de datos y que trabajando con el objeto
DataSet hemos realizado una inserción de datos y que a continuación, queremos propagar
dicha inserción a la base de datos, deberemos hacer uso del método Insert del objeto

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 506


DataAdapter.
El objeto DataAdapter se encargará de llamar al comando apropiado para cada una de las
filas que han sido modificadas en un determinado DataSet.

Esto lo realizará siempre a través del método Update.

Trabajando con un ejemplo

La mejor manera de ver esto es con un ejemplo que nos ayude a entender mejor como
funciona la inserción de datos a través del objeto DataAdapter.

Tenga en cuenta además, que la actualización y el borrado de datos funciona de la


misma manera. Iniciaremos un nuevo proyecto de formulario Windows y en él
insertamos los componentes SqlConnection, SqlDataAdapter, DataSet y SqlCommand.
Para el componente SqlConnection, estableceremos la propiedad ConnectionString con
el valor:
server=.;uid=sa;password=VisualBasic;database=MSDNVideo

A continuación seleccionaremos el componente SqlDataAdapter y modificaremos la


propiedad SelectCommand > Connection como vimos en el capítulo anterior.

De la lista de posibles conexiones que le aparezca, seleccione la conexión SqlConnection1.


Finalmente, inserte un control Button y un control DataGridView en el formulario. Éste
quedará como se indica en la figura.

Formulario con los componentes y controles insertados en él Figura 1

Finalmente, escribiremos el código necesario para ejecutar nuestra aplicación tal y como
queremos. Este es el que se detalla a continuación:

Public Class Form1

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 507


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
' Establecemos la cadena SQL a utilizar
SqlDataAdapter1.SelectCommand.CommandText = "SELECT NIF, Nombre,
Apellido1, Apellido2, Telefono, Email, Direccion, Ciudad, Provincia, CP FROM
SOCIOS"
' Abrimos la Conexión
SqlConnection1.Open()

' Rellenamos el DataSet con el contenido de la instrucción sql


SqlDataAdapter1.Fill(DataSet1, "Ejemplo")
' Cerramos la Conexión
SqlConnection1.Close()
' Asociamos el control DataGridView al DataSet
DataGridView1.DataSource = DataSet1.Tables("Ejemplo")
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles Button1.Click
' Declaramos un objeto DataRow para insertar en él los nuevos datos
Dim MiDataRow As Data.DataRow
' Creamos una nueva fila en el DataSet
MiDataRow = DataSet1.Tables("Ejemplo").NewRow()
' Insertamos los datos en el DataSet
MiDataRow("NIF") = "222222"
MiDataRow("Nombre") = "María"
MiDataRow("Apellido1") = "Juárez"
MiDataRow("Apellido2") = "Fernández"
MiDataRow("Telefono") = "1112233"
MiDataRow("Email") = "maría@cuentademail.com"
MiDataRow("Direccion") = "C\ Fernández de los Ríos, 77"
MiDataRow("Ciudad") = "Valladolid"
MiDataRow("Provincia") = "Valladolid"
MiDataRow("CP") = "11111"
DataSet1.Tables("Ejemplo").Rows.Add(MiDataRow)

' Si el DataSet tiene cambios ?


If DataSet1.HasChanges Then
' Indicamos la instrucción SQL correspondiente

SqlCommand1.CommandText = "INSERT INTO SOCIOS(NIF,


Nombre, Apellido1, Apellido2, Telefono, Email, Direccion, Ciudad, Provincia, CP)
VALUES(@NIF, @Nombre, @Apellido1, @Apellido2, @Telefono, @Email,
@Direccion, @Ciudad, @Provincia, @CP)"

' Establecemos para el comando, la (conexión) que utilizaremos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 508


SqlCommand1.Connection = SqlConnection1
' Le indicamos al DataAdapter, cuál es el comando de inserción que usaremos
SqlDataAdapter1.InsertCommand = SqlCommand1
' Añadimos los parámetros y comandos correspondientes
' para cada campo a añadir en la base de datos

SqlCommand1.Parameters.Add("@NIF", Data.SqlDbType.NChar, 10, "NIF")


SqlCommand1.Parameters.Add("@Nombre",
Data.SqlDbType.NVarChar, 50, "Nombre")
SqlCommand1.Parameters.Add("@Apellido1",
Data.SqlDbType.NVarChar, 50, "Apellido1")
SqlCommand1.Parameters.Add("@Apellido2",
Data.SqlDbType.NVarChar, 50, "Apellido2")
SqlCommand1.Parameters.Add("@Telefono",
Data.SqlDbType.NVarChar, 13, "Telefono")
SqlCommand1.Parameters.Add("@Email",
Data.SqlDbType.NVarChar, 50, "Email")
sqlCommand1.Parameters.Add("@Direccion",
Data.SqlDbType.NVarChar, 100, "Direccion")
SqlCommand1.Parameters.Add("@Ciudad",
Data.SqlDbType.NVarChar, 50, "Ciudad")
SqlCommand1.Parameters.Add("@Provincia",
Data.SqlDbType.NVarChar, 50, "Provincia")
SqlCommand1.Parameters.Add("@CP", Data.SqlDbType.NChar, 5,"CP")

' Abrimos la conexión


SqlConnection1.Open()
' Realizamos la inserción de datos desde el DataSet a través del DataAdapter
SqlDataAdapter1.Update(DataSet1, "Ejemplo")
' Cerramos la conexión
SqlConnection1.Close()
' Indicamos con un mensaje que la inserción de datos se ha realizado con éxito
MessageBox.Show("Datos insertados correctamente")
End If
End Sub
End Class

Por último, ejecute la aplicación. Si todo ha ido correctamente, los datos habrán quedado
correctamente insertados en la base de datos. Un ejemplo de nuestra aplicación en
ejecución es la que puede verse en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 509


Aplicación de ejemplo de inserción de datos con DataAdapter y DataSet en ejecución

Como vemos, el uso de DataAdapter en el caso de manipular datos, varía ligeramente. Sin
embargo, no es mucho más complicado con la actualización y borrado de datos. De hecho,
la forma de actuar es la misma como veremos a continuación.

2.7.2.- Actualizando datos a través del objeto DataAdapter

De la misma manera que hemos insertado datos en nuestra base de datos, debemos hacer a
la hora de actualizar los mismos. Sobre la base del ejemplo anterior (componentes y
controles), escriba o modifique el siguiente código:

Public Class Form1


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
' Establecemos la cadena SQL a utilizar
SqlDataAdapter1.SelectCommand.CommandText = "SELECT NIF, Nombre,
Apellido1, Apellido2, Telefono, Email, Direccion, Ciudad, Provincia, CP FROM
SOCIOS"
' Abrimos la Conexión SQL
SqlConnection1.Open()
SqlDataAdapter1.Fill(DataSet1, "Ejemplo")
' Cerramos la Conexión
SqlConnection1.Close()
' Asociamos el control DataGridView al DataSet
DataGridView1.DataSource = DataSet1.Tables("Ejemplo")
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles Button1.Click

' En nuestro ejemplo, sabemos que queremos modificar

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 510


' la fila 2, columna 4 (todos los elementos empiezan por 0)
DataSet1.Tables("Ejemplo").Rows(1)(4) = "1112234"
' Si el DataSet tiene cambios ?
If DataSet1.HasChanges Then
' Indicamos la instrucción SQL correspondiente

SqlCommand1.CommandText = "UPDATE SOCIOS SET


Telefono=@Telefono WHERE NIF=@NIF"

' Establecemos para el comando, la (conexión) que utilizaremos


SqlCommand1.Connection = SqlConnection1
' Le indicamos al DataAdapter, cuál es el comando de actualización que usaremos
SqlDataAdapter1.UpdateCommand = SqlCommand1
' Añadimos los parámetros y comandos orrespondientes
' para cada campo a actualizar en la base de datos
SqlCommand1.Parameters.Add("@NIF", Data.SqlDbType.NChar,10, "NIF")
SqlCommand1.Parameters.Add("@Nombre",
Data.SqlDbType.NVarChar, 50, "Nombre")
SqlCommand1.Parameters.Add("@Apellido1",
Data.SqlDbType.NVarChar, 50, "Apellido1")
SqlCommand1.Parameters.Add("@Apellido2",
Data.SqlDbType.NVarChar, 50, "Apellido2")
SqlCommand1.Parameters.Add("@Telefono",
Data.SqlDbType.NVarChar, 13, "Telefono")
SqlCommand1.Parameters.Add("@Email",
Data.SqlDbType.NVarChar, 50, "Email")
SqlCommand1.Parameters.Add("@Direccion",
Data.SqlDbType.NVarChar, 100, "Direccion")
SqlCommand1.Parameters.Add("@Ciudad",
Data.SqlDbType.NVarChar, 50, "Ciudad")
SqlCommand1.Parameters.Add("@Provincia",
Data.SqlDbType.NVarChar, 50, "Provincia")

SqlCommand1.Parameters.Add("@CP", Data.SqlDbType.NChar, 5, "CP")


' Abrimos la conexión
SqlConnection1.Open()
' Realizamos la actualización de datos desde el DataSet a través del DataAdapter
SqlDataAdapter1.Update(DataSet1, "Ejemplo")
' Cerramos la conexión
SqlConnection1.Close()
' Indicamos con un mensaje que la actualización de datos se ha realizado con éxito
MessageBox.Show("Datos actualizados correctamente")
End If
End Sub
End Class

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 511


Nuestro ejemplo en ejecución es el que se puede ver en la figura 1.

Aplicación de ejemplo de actualización de datos con DataAdapter y DataSet

2.7.3.- Eliminando datos a través del objeto DataAdapter


De igual forma sucede con la eliminación de datos utilizando para ello el objeto
DataAdapter junto al objeto DataSet.

Utilizaremos nuevamente en este caso, la base del ejemplo anterior (componentes y


controles), y escribiremos el siguiente código:

Public Class Form1


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
' Establecemos la cadena SQL a utilizar
SqlDataAdapter1.SelectCommand.CommandText = "SELECT NIF,Nombre,
Apellido1, Apellido2, Telefono, Email, Direccion, Ciudad,Provincia, CP FROM
SOCIOS"
' Abrimos la Conexión
SqlConnection1.Open()
' Rellenamos el DataSet con el contenido de la instrucción SQL

SqlDataAdapter1.Fill(DataSet1, "Ejemplo")
' Cerramos la Conexión
SqlConnection1.Close()
' Asociamos el control DataGridView al DataSet
DataGridView1.DataSource = DataSet1.Tables("Ejemplo")
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As


System.EventArgs) Handles Button1.Click
' En nuestro ejemplo, sabemos que queremos eliminar

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 512


' la fila 2 (todos los elementos empiezan por 0) por lo que la fila 2 es aquí la 1
DataSet1.Tables("Ejemplo").Rows(1).Delete()
' Si el DataSet tiene cambios ?
If DataSet1.HasChanges Then
' Indicamos la instrucción SQL correspondiente
SqlCommand1.CommandText = "DELETE SOCIOS WHERE NIF=@NIF"
' Establecemos para el comando, la (conexión) que utilizaremos
SqlCommand1.Connection = SqlConnection1
' Le indicamos al DataAdapter, cuál es el comando de eliminación que usaremos
SqlDataAdapter1.DeleteCommand = SqlCommand1
' Añadimos los parámetros y comandos correspondientes
' para cada campo a actualizar en la base de datos
SqlCommand1.Parameters.Add("@NIF", Data.SqlDbType.NChar,10, "NIF")
SqlCommand1.Parameters.Add("@Nombre",
Data.SqlDbType.NVarChar, 50, "Nombre")

SqlCommand1.Parameters.Add("@Apellido1",
Data.SqlDbType.NVarChar, 50, "Apellido1")

SqlCommand1.Parameters.Add("@Apellido2",
Data.SqlDbType.NVarChar, 50, "Apellido2")

SqlCommand1.Parameters.Add("@Telefono",
Data.SqlDbType.NVarChar, 13, "Telefono")

SqlCommand1.Parameters.Add("@Email",
Data.SqlDbType.NVarChar, 50, "Email")

SqlCommand1.Parameters.Add("@Direccion",
Data.SqlDbType.NVarChar, 100, "Direccion")

SqlCommand1.Parameters.Add("@Ciudad",
Data.SqlDbType.NVarChar, 50, "Ciudad")

SqlCommand1.Parameters.Add("@Provincia",
Data.SqlDbType.NVarChar, 50, "Provincia")
SqlCommand1.Parameters.Add("@CP", Data.SqlDbType.NChar, 5,"CP")

' Abrimos la conexión


SqlConnection1.Open()
' Realizamos la eliminación de datos desde el DataSet a través del DataAdapter
SqlDataAdapter1.Update(DataSet1, "Ejemplo")
' Cerramos la conexión
SqlConnection1.Close()
' Indicamos con un mensaje que la eliminación de datos se ha realizado con éxito
MessageBox.Show("Datos eliminados correctamente")

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 513


End If
End Sub
End Class

Nuestro ejemplo en ejecución es el que se puede ver en la figura .

Aplicación de ejemplo de eliminación de datos con DataAdapter y DataSet

2.8.- Trabajando con tablas Maestro Detalle.

El desarrollador de aplicaciones que debe trabajar con datos y fuentes de datos relacionadas
entre sí, encuentra con frecuencia problemas de desarrollo en aplicaciones con datos
interrelacionados. Además, este tipo de aplicaciones, consumen gran parte del tiempo de
desarrollo y son por lo general, acciones repetitivas.
Supongamos como ejemplo general, la tabla Socios de un videoclub. Además, relacionemos
los socios del videoclub, con una tabla Alquileres, para saber si un socio determinado tiene
películas alquiladas, y en ese caso, saber cuáles.

Este sencillo ejemplo, es un claro exponente de una aplicación que relaciona datos maestro
detalle. Ambas tablas deben estar relacionadas para recopilar la información que se
necesite en un momento dado.
Los datos maestros serían expuestos por los socios del videoclub, mientras que los datos
detalle estarían relacionados con los datos de los alquileres de los socios.
En nuestro caso, vamos a cambiar las palabras maestro y detalle por padre e hijo, y a partir
de ahora, nos referiremos a padre como la tabla Socios, e hijo como la tabla Alquileres. De
esta forma, ubicaremos sin problemas ambos conceptos dentro del entorno de Visual Studio
2008, ya que éste tiene alguna ligera connotación que podría infundirnos a error como
observará más adelante.

Por suerte, Visual Studio nos proporciona un conjunto de herramientas, que hace que

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 514


realizar una aplicación Windows con todas las características de una aplicación maestro
detalle, sea un auténtico juego de niños, que nos llevará aproximadamente un minuto de
nuestro tiempo como mucho. ¿No me cree?. Continúe el capítulo, y se sorprenderá de lo
que Visual Studio 2008 puede hacer por usted.

2.9.- Configurando la fuente de datos

Trabajar con fuentes de datos requiere como tarea inicial, que tengamos listo y preparado
un origen de fuentes de datos válido. Para esta tarea, deberemos configurar la fuente de
datos que vamos a utilizar, algo que vamos a aprender a hacer a continuación.

Configurando el origen de la fuente de datos


Iniciaremos una nueva aplicación Windows con Visual Studio y seleccionaremos el menú
Datos > Mostrar orígenes de datos como se indica en la figura

Menú para mostrar los orígenes de datos

En este punto, aparecerá una ventana como la que se muestra en la figura.

Ventana de orígenes de datos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 515


Como podemos apreciar, la ventana no tiene por defecto ningún origen de datos asignado,
además, esta ventana inicialmente, no está anclada a ningún sitio del entorno. Para situarla
en un lugar específico del entorno, haga clic sobre la ventana y arrástrela sobre la parte en
la que desee situarla, como se indica por ejemplo, en la figura

La ventana orígenes de datos podemos situarla dónde deseemos dentro de Visual


Studio

En este punto, la ventana de orígenes de datos, quedará anclada en el entorno de


desarrollo, como se muestra en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 516


La ventana orígenes de datos anclada en Visual Studio

Cada uno, puede situar esta ventana dónde considere oportuno. En mi caso la he situado
entre las ventanas del Explorador de soluciones y de Propiedades, pero podemos situarla
dónde consideremos oportuno. Sobre la configuración del origen de datos, haga clic sobre
la opción Agregar nuevo origen de datos... como se indica en la figura

Opción para agregar un nuevo origen de datos

Aparecerá una ventana como la que se muestra en la figura 6 en la cuál indicaremos el lugar
de dónde la aplicación obtendrá los datos, y que en nuestro caso será de una Base de datos.

Como tipo de origen de datos elegiremos una Base de datos

Una vez seleccionado la opción de Base de datos como tipo de origen de datos,
presionaremos el botón Siguiente.
En la siguiente ventana, elegiremos la conexión de la base de datos que vamos a utilizar, o
presionaremos sobre el botón Nueva conexión... sino tenemos seleccionada la conexión que
queremos utilizar.
En la figura podemos ver como hemos establecido la conexión con nuestra fuente de

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 517


datos, que utilizaremos en nuestro ejemplo de creación de la aplicación de acceso a
datos maestro detalle.

Ventana dónde elegimos la conexión de datos

A continuación, haremos clic en el botón Siguiente.

En la nueva ventana que aparece ahora dentro del asistente para la creación del origen de
datos, indicaremos el nombre de la cadena de conexión que crearemos. En nuestro caso, no
modificaremos el nombre de la cadena de conexión, dejándola por defecto como se muestra
en la figura

Asignamos un nombre para el nombre de la cadena de conexión

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 518


A continuación, haremos clic sobre el botón Siguiente.

En este punto, el asistente se conecta a la base de datos para recuperar la


información de la base de datos y mostrarla en la ventana del asistente como se
muestra en la figura

Ventana con los objetos de la base de datos seleccionada

A continuación, despliegue el objeto Tablas y seleccione las tablas Alquileres y Socios como
se indica en la figura

Selección de los objetos de la base de datos seleccionada

Una vez que hemos seleccionado los objetos de la base de datos, haremos clic sobre el botón
Finalizar para que el asistente concluya las opciones añadidas al asistente. La ventana del

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 519


origen de datos, quedará ahora configurado de una forma similar a la que se presenta en la
figura

Ventana de origen de datos con la configuración añadida

A partir de aquí, deberemos preparar las tablas del origen de datos para que se comporten
como auténticos datos e informaciones maestro detalle. Esto es lo que veremos en el
siguiente módulo.

2.9.1.- Preparando el origen de datos

Ya hemos aprendido a añadir nuestro origen de datos, y ahora aprenderemos a prepararlo


para poder utilizarlo posteriormente en la aplicación Windows.
La preparación del origen de datos, nos permitirá seleccionar que tabla o datos queremos
que actúen como maestro y cuales como detalle, o dicho de otra forma, que datos queremos
que sean padre y cuales hijo.
Nuestro objetivo principal es mostrar la tabla Alquileres como tabla hijo y la tabla Socios
como padre de la tabla anterior.

Prepararemos e incrustaremos primero la tabla Socios dentro del formulario Windows como
Detalle de la información, y posteriormente insertaremos la tabla Alquileres dentro del
formulario.
Por último, asignaremos alguna relación que permita trabajar con las dos tablas en nuestro
formulario Windows sin perder la conexión entre ambas tablas y permitiéndonos acceder a
la información que nos proporciona dicha relación.

Preparando la tabla padre


Lo primero que haremos será preparar la tabla padre para poderla añadir al formulario
Windows. Por esa razón, haremos clic sobre la tabla Socios de la ventana de Orígenes de
datos como se indica en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 520


Tabla Socios de la ventana de orígenes de datos

En la ventana de Orígenes de datos y en concreto con la tabla Socios desplegada,


centraremos nuestra atención en el campo NIF como se indica en la figura

Campo NIF de la tabla Socios

Pulse sobre la lista desplegable que aparece a la derecha del campo NIF y seleccione la
opción Label como se indica en la figura

Lista desplegable con la opción Label seleccionada como campo de la tabla


desplegada

En este caso, la ventana de Orígenes de datos quedará informada tal y como se indica
en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 521


Campo NIF modificado en la ventana de Orígenes de datos

A continuación, haremos clic sobre la tabla Socios como se indica en la figura, y


posteriormente presionaremos sobre la lista desplegable que aparece a la derecha de la
tabla.

Tabla Socios seleccionada en la ventana de Orígenes de datos

Si hacemos clic sobre la lista desplegable, aparecerá una lista de opciones o posibilidades,
para indicar cómo queremos que sean los campos de la tabla seleccionada con respecto a que
tipo de controles queremos que sean. Esto es lo que se indica en la figura

Lista desplegable de la tabla Socios de la ventana de Orígenes de datos

Por defecto, una tabla queda determinada con un icono que representa el control
DataGridView, aunque se puede modificar la representación que deseamos tengan los datos
dentro de un formulario seleccionando cualquiera de las opciones que tenemos de la lista
desplegable. Estas opciones pueden ser cualquiera de las siguientes:
Representa los datos volcados dentro de un control DataGridView
Representa los datos volcados dentro de controles estándar como TextBox u otros
controles para reflejarla como Detalle de la información

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 522


No representa ningún control como tipo de control de volcado de datos

En el caso de la tabla Socios que usaremos como tabla padre, cambiaremos la


representación por defecto de DataGridView para indicarle que nos represente la
información en controles, tal y como se indica en la figura

Tabla Socios seleccionada en la ventana de Orígenes de datos como Detalle

Ahora que tenemos la tabla maestra ya preparada, pasaremos a preparar la


tabla hija.

Preparando la tabla hija


Ahora que ya tenemos preparada la tabla tabla padre, prepararemos la tabla hija de los
alquileres de las películas de video, para poder usar su información dentro del formulario
Windows. Por esa razón, haga clic sobre la tabla Alquileres de la ventana de Orígenes
de datos como se indica en la figura

Tabla Alquileres de la ventana de orígenes de datos

Dentro de la ventana de Orígenes de datos y en concreto de la tabla Alquileres


desplegada, centraremos nuestra atención en el campo AlquilerID y SocioNIF como
se indica en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 523


Campos AlquilerID y SocioNIF de la tabla Alquileres

Sobre el campo AlquilerID y SocioNIF, haremos una pequeña modificación. Pulse sobre la
lista desplegable que aparece a la derecha del campo AlquilerID y SocioNIF y seleccione la
opción Label como se indica en la figura

Lista desplegable de opciones de un campo de la tabla desplegada

De esta manera, el campo AlquilerID y SocioNIF quedarán modificados en la ventana


Orígenes de datos como se indica en la figura

Campo AlquilerID y SocioNIF modificados en la ventana de Orígenes de datos

A continuación, haremos clic sobre la tabla Alquileres como se indica en la figura, y


posteriormente presionaremos sobre la lista desplegable que aparece a la derecha de la tabla.

Tabla Alquileres seleccionada en la ventana de Orígenes de datos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 524


Nos aseguraremos que está seleccionada la opción DataGridView que es la que
aparece por defecto. Esto es lo que se indica en la figura

En la tabla Alquileres, nos aseguraremos de seleccionar la opción DataGridView

Una vez que tenemos las tabla maestra y detalle preparadas para utilizarlas, las añadiremos
al formulario Windows para que tengan el funcionamiento esperado.

2.9.2.- Incrustando los datos maestro detalle

Ya sabemos como crear un origen de datos, también sabemos como preparar los datos
maestro y detalle, y por último, lo que nos queda es insertar esos datos en el formulario,
y relacionar todos sus datos para que funcionen de la forma esperada. A continuación,
veremos como llevar a cabo esta tarea y aprenderemos a hacerlo posible de forma muy
rápida y sencilla.

Incrustando la tabla padre en el formulario

Nuestra primera acción, será incrustar en el formulario los datos o tabla padre, que en
nuestro caso es la formada por la tabla Socios.
Para situar los datos de la tabla Socios dentro de un formulario y en concreto como una
información de detalle, bastará con arrastrar y soltar la tabla Socios sobre el formulario
como se indica en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 525


Para presentar la información como detalle, arrastraremos la tabla Socios de
la ventana Orígenes de datos sobre el formulario Windows

Observaremos que Visual Studio, generará por nosotros un conjunto de componentes y


controles, que por defecto tendrá una apariencia similar a la que se presenta en la figura

Controles y Componentes de la tabla maestra añadidos al formulario Windows

Observe por un momento, que el campo NIF que declaramos como Label en la ventana de
Orígenes de datos, aparece como tal en el formulario, tal y como se indica en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 526


Campo NIF de la tabla, representado como un control Label en el formulario
Windows

Si ejecutamos nuestra aplicación, observaremos que esta actúa como una típica aplicación
de acceso a datos que nos permite navegar a través de los campos de la tabla Socios, tal y
como se indica en la figura

Aplicación en ejecución de la tabla de detalle incrustada en el formulario Windows

A continuación, insertaremos en el formulario la tabla Alquileres y relacionaremos ambas


tablas para que se muestren los datos relacionados, dentro del formulario Windows.

Incrustando la tabla hija en el formulario

Ya tenemos la tabla padre insertada en nuestro formulario Windows. Nuestra segunda


acción, será la de incrustar en el formulario los datos o tabla hoja, que en nuestro caso es
la formada por la tabla Alquileres, la cuál además, posee una relación entre campos con la
tabla Socios insertada anteriormente.
Para llevar a cabo esta acción arrastraremos y soltaremos la tabla Alquileres sobre el
formulario como se indica en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 527


Para presentar la información de la tabla Alquileres, arrastraremos la tabla de
la ventana Orígenes de datos sobre el formulario Windows

Como podemos observar, el entorno de trabajo ha hecho por nosotros el trabajo más
complejo para representar los datos de forma rápida y sencilla.
El esquema de datos tipados, aparecía ya en nuestro proyecto cuando asignamos el
correspondiente origen de datos. Ahora lo que ha ocurrido, es que al arrastrar y soltar
la tabla padre Socios de la ventana de Orígenes de datos, en el entorno se ha añadido un
componente de nombre MSDNVideoDataSet que es el que permitirá relacionar el DataSet
tipado con nuestros datos.
Este componente será usado por la relación maestro detalle de las dos tablas añadidas al
formulario.
En la figura, podemos ver el esquema añadido a nuestro proyecto, y el componente del
que estamos hablando.

Esquema del DataSet tipado añadido al proyecto y su componente de relación

Ejecute la aplicación y observe el comportamiento de la misma.

Observará por lo tanto, que los datos entre detalle y maestra, no están relacionados. Si
navegamos a través de los datos de detalle a través del objeto SociosBindingNavigator, el

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 528


control DataGridView no representa la relación de los datos seleccionados.

Esto es lo que se muestra en la figura.

Ejecución de la aplicación confirmando que los datos mostrados no están relacionados

A continuación, la tarea que nos queda para completar el correcto funcionamiento de


nuestra aplicación, es la de relacionar la tabla detalle y la tabla maestra entre sí, para
que los datos que se muestran en la aplicación, estén relacionados entre sí.

Relacionando la tabla padre con la tabla hija

La tarea más sencilla es la de relacionar la tabla detalle con la tabla maestra. Es una tarea
sencilla, porque Visual Studio nos proporciona las herramientas necesarias para simplificar
al máximo esta tarea.

Para llevar a cabo esta tarea, haga clic sobre el control DataGridView que corresponde
a los datos de la tabla maestra, y acceda a la ventana de Propiedades.
Dentro de la ventana de Propiedades, acceda a la propiedad DataSource como se indica
en la figura.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 529


Propiedad DataSource del control DataGridView de la información maestra

Despliegue esta propiedad, y de la lista desplegable que aparece, seleccione la


opción FK_Alquileres_Socios como se indica en la figura

Asignación de la clave de relación entre las tablas

Cuando se asigna el campo de relación de las tablas, dentro de la aplicación se añade esta
relación para que cuando naveguemos entre los datos de la tabla Socios aparezca toda la
información de la tabla Alquileres relacionada con la tabla Socios.

Esto de lo que hablamos, está supeditado por el componente


FK_Alquileres_SociosBindingSource que es lo que se indica en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 530


Controles y componentes incluido el de relación entre tablas, añadidos al formulario
Windows

Para finalizar, ejecutaremos nuestra aplicación y comprobaremos que el funcionamiento de


esta, incluida la relación entre tablas, funciona como esperábamos. En la figura, podemos
observar el comportamiento de nuestra aplicación en ejecución.

Aplicación en ejecución, mostrando la correcta relación entre las tablas

2.9.3.- Manipulando los datos maestro detalle

Obviamente, los datos maestro detalle no nos sirve únicamente para insertar las tablas de
datos en un formulario, mostrarlos y navegar por ellos. Además de esto, podemos también
manipular los datos maestro detalle, modificarlos, actualizarlos, borrarlos, sin hacer
ninguna acción adicional. El control BindingNavigator ya proporciona todas las

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 531


características necesarias para realizar estas acciones.

Podemos personalizar el control para permitir o denegar estas acciones. Además, dentro de
la ventana de Orígenes de datos, podemos seleccionar diferentes campos de las tablas y
cambiar el tipo de control en el que queremos representar sus datos. A continuación veremos
un breve ejemplo de como manipular datos para que nos sirva de aprendizaje de cómo hacer
esto posible.

Modificando datos

Ejecute la aplicación de ejemplo que hemos diseñado hasta ahora y sitúese en alguno de
sus campos. Centrándonos en la información de la tabla Socios, cambiaremos un campo
determinado, como el que se muestra en la figura

Modificaremos el valor de un campo para que nos sirva de ejemplo


Acto seguido, cuando hayamos realizado la modificación, haremos clic sobre la opción
de Guardar datos, tal y como se muestra en la figura.

Opción del control BindingNavigator para guardar los datos modificados

Como vemos, la manipulación de datos es realmente sencilla y en la relación de datos


mostrada, no tiene porqué presentarnos ninguna dificultad.

Insertando y eliminando datos

Si queremos agregar datos, deberemos hacer clic sobre la opción Agregar nuevo del
control BindingNavigator como se muestra en la figura

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 532


Añadir un registro nuevo es realmente sencillo
De la misma manera funciona el mecanismo para eliminar un registro, tal y como se
muestra en la figura

Eliminar un registro de forma Rápida

2.-10.- Vistas y ordenación de datos con la clase DataView


La clase DataView nos permite la aplicación de vistas personalizadas a partir de una tabla
contenida en un DataSet, así como la ordenación y búsqueda de filas.
Partiendo de un objeto DataTable situado en un DataSet, vamos a definir varias vistas
simultáneamente, ordenar y buscar registros, con la ventaja de que el consumo de recursos
es menor, puesto que los objetos DataView se alimentan del mismo DataTable. Para realizar
algunas pruebas, se acompaña el proyecto Vistas
El DataSet del formulario de pruebas va a estar compuesto por dos tablas. El Código
fuente muestra el evento de carga del formulario.
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Handles MyBase.Load
' crear conexión
Dim oConexion As New SqlConnection()
oConexion.ConnectionString = "Server=(local);" & _
"Database=Northwind;uid=sa;pwd=;"
'crear dataset
oDataSet = New DataSet()
Dim oDataAdapter As SqlDataAdapter
' crear un adaptador de datos para la tabla Customers
oDataAdapter = New SqlDataAdapter("SELECT * FROM Customers",
oConexion)
' añadir tabla al dataset con el adaptador
oDataAdapter.Fill(oDataSet, "Customers")
oDataAdapter = Nothing
' crear un adaptador de datos para la tabla Products
oDataAdapter = New SqlDataAdapter("SELECT * FROM Products",
oConexion)
' añadir tabla al dataset con el adaptador

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 533


oDataAdapter.Fill(oDataSet, "Products")
oDataAdapter = Nothing
End Sub

Vistas por código y DefaultView


Podemos crear una vista instanciando un objeto de la clase DataView, o también
obteniendo la denominada vista por defecto de una tabla de un DataSet, a través de la
propiedad DefaultView del objeto DataTable. La opción de menú Vistas + Normal del
formulario, crea dos vistas de esta manera. Ver Código fuente .
Private Sub mnuNormal_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuNormal.Click
' crear una vista por código y asignarla a un datagrid
Dim dvNormal As DataView
dvNormal = New DataView(oDataSet.Tables("Customers"))
Me.grdDatos.CaptionText = "Customers"
Me.grdDatos.DataSource = dvNormal
' tomar la vista por defecto de una tabla
' del dataset y asignarla a un datagrid
Me.grdDatosBIS.CaptionText = "Products"
Me.grdDatosBIS.DataSource = oDataSet.Tables("Products").DefaultView
End Sub
La Figura muestra estas vistas en sendos DataGrid del formulario.

Objetos DataView creados por código y obtenido de DataTable.DefaultView.


Filtros con objetos DataView
La propiedad RowFilter de la clase DataView nos permite asignar a este objeto, una
cadena con la expresión de filtro, que en una consulta en lenguaje SQL sería la parte
correspondiente a la partícula Where.
El Código fuente muestra el código de la opción de menú Vistas + País, del
formulario de ejemplo, en la que se crea un filtro que se muestra posteriormente en un
DataGrid.
Private Sub mnuPais_Click(ByVal sender As System.Object, ByVal e As

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 534


System.EventArgs) Handles mnuPais.Click
' crear dataview
Dim oDataView As New DataView()
oDataView.Table = oDataSet.Tables("Customers")
' establecer un filtro
oDataView.RowFilter = "Country='Spain'"
Me.grdDatos.CaptionText = "Filtrar Customers por país Spain"
Me.grdDatos.DataSource = oDataView
End Sub
La Figura muestra las filas de la tabla con el filtro aplicado.

DataView con filtro.


Como hemos comentado anteriormente, a partir de un DataTable podemos obtener
varios filtros mediante distintos objetos DataView, sin que ello suponga una
penalización en el consumo de recursos. Para demostrar este punto, la opción Vistas +
Combinada, crea una vista basada en un filtro combinado, y una vista normal, ambas
empleando la misma tabla base. Veamos el Código fuente
Private Sub mnuCombinada_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuCombinada.Click
' tomar la tabla Customers del dataset y aplicar...
' ...filtro combinado por dos campos y depositar en un datagrid
Dim oDataView As New DataView()
oDataView.Table = oDataSet.Tables("Customers")
oDataView.RowFilter = "ContactTitle LIKE '%Manager%' AND Country IN
('Spain','USA')"
Me.grdDatos.CaptionText = "Filtro combinado por campos ContactTitle y
Country"
Me.grdDatos.DataSource = oDataView
' ...filtro por un campo y depositar en otro datagrid
Dim oDV As New DataView()
oDV.Table = oDataSet.Tables("Customers")
oDV.RowFilter = "ContactName LIKE '%an%'"
Me.grdDatosBIS.CaptionText = "Filtro por campo ContactName"
Me.grdDatosBIS.DataSource = oDV
End Sub

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 535


La Figura muestra el formulario con los diversos filtros establecidos

Filtros combinados con objetos DataView.


Búsquedas con DataView
Estableciendo el adecuado filtro a un objeto DataView, podemos realizar búsquedas de
registros en tablas, como muestra el Código fuente, correspondiente a la opción de menú
Vistas + Buscar fila, del formulario de ejemplo. Deberemos previamente, haber escrito
en el TextBox del formulario, el identificador de la tabla Customers a buscar.
Private Sub mnuBuscarFila_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuBuscarFila.Click
' crear un dataview y buscar una fila en la vista
' estableciendo un filtro
Dim oDataView As New DataView()
oDataView.Table = oDataSet.Tables("Customers")
oDataView.RowFilter = "CustomerID = '" & Me.txtCustomerID.Text & "'"
Me.grdDatosBIS.CaptionText = "Buscar ID cliente: " &
Me.txtCustomerID.Text
Me.grdDatosBIS.DataSource = oDataView
End Sub
En la Figura vemos el resultado de una búsqueda, mostrado en uno de los
DataGrid del formulario.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 536


Búsqueda de una fila en una tabla de un DataSet, empleando un DataView.
Ordenación de filas mediante DataView
Para ordenar las filas en un DataView emplearemos su propiedad Sort, asignándole una
cadena con el nombre de columna/s a ordenar, tal y como muestra el Código fuente ,
de la opción de menú Ordenación + Normal, en el formulario del ejemplo.
Private Sub mnuOrdNormal_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuOrdNormal.Click
' crear dataview y ordenar las filas con la propiedad Sort
Dim oDataView As New DataView()
oDataView.Table = oDataSet.Tables("Customers")
oDataView.Sort = "Country"
Me.grdDatos.CaptionText = "Ordenar por campo Country"
Me.grdDatos.DataSource = oDataView
End Sub
Veamos el resultado al ejecutar en la Figura
Si necesitamos ordenar por múltiples columnas de la tabla, sólo tenemos que asignar a Sort
una cadena con la lista de columnas requeridas. Ver Código fuente .

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 537


DataView ordenando las filas por la columna Country.
oDataView.Sort = "Country, PostalCode"
También es factible asignar a un DataView una combinación de filtro y ordenación,
utilizando en la misma operación las propiedades RowFilter y Sort. El menú del
formulario Ordenación + Con filtro realiza este trabajo, que vemos en el Código fuente .
Private Sub mnuOrdenFiltro_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles mnuOrdenFiltro.Click
Dim oDataView As New DataView()
oDataView.Table = oDataSet.Tables("Customers")
' establecer un filtro al dataview
oDataView.RowFilter = "Country='USA'"
' ordenar las filas del filtro
oDataView.Sort = "City"
Me.grdDatos.CaptionText = "Filtrar por USA. Ordenar por campo City"
Me.grdDatos.DataSource = oDataView
End Sub
Los datos con el filtro y orden podemos verlos en el DataGrid del formulario, que
muestra la Figura .

Resultado de DataView con filtro y orden.


2.11.-Obtener el esquema de un DataSet
El esquema de un DataSet consiste en toda la información contenida por este objeto,
acerca de los nombres de tablas, columnas, relaciones, etc.; es decir, se trata de
metainformación sobre los datos que contiene el DataSet.
Podemos obtener estos metadatos del DataSet recorriendo la colección que nos interese en
cada caso: Tables, Columns, etc. El Código fuente muestra como tras crear un DataSet,
recorremos sus tablas, y dentro de estas, sus columnas, mostrando la información obtenida
en un ListBox.
Private Sub btnEsquema_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnEsquema.Click
' crear conexión
Dim oConexion As New SqlConnection()
oConexion.ConnectionString = "Server=(local);" & _
"Database=Northwind;uid=sa;pwd=;"
' crear dataset
Dim oDataSet As New DataSet()
' crear adaptadores de datos para las tablas

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 538


' y añadir cada tabla al dataset con el adaptador
Dim oDataAdapter As SqlDataAdapter
oDataAdapter = New SqlDataAdapter("SELECT * FROM Customers",
oConexion)
oDataAdapter.Fill(oDataSet, "Customers")
oDataAdapter = Nothing
oDataAdapter = New SqlDataAdapter("SELECT * FROM Orders", oConexion)
oDataAdapter.Fill(oDataSet, "Orders")
oDataAdapter = Nothing
oDataAdapter = New SqlDataAdapter("SELECT * FROM Products",
oConexion)
oDataAdapter.Fill(oDataSet, "Products")
oDataAdapter = Nothing
oDataAdapter = New SqlDataAdapter("SELECT * FROM Territories",
oConexion)
oDataAdapter.Fill(oDataSet, "Territories")
oDataAdapter = Nothing
' crear un objeto tabla y columna para mostrar
' la información del esquema que el dataset contiene
Dim oDataTable As DataTable
Dim oDataColumn As DataColumn
Me.lstEsquema.Items.Add("Estructura del DataSet")
' recorrer la colección de tablas del DataSet
For Each oDataTable In oDataSet.Tables
Me.lstEsquema.Items.Add("Tabla: " & oDataTable.TableName)
Next
' recorrer la colección de columnas de la tabla
For Each oDataColumn In oDataTable.Columns
Me.lstEsquema.Items.Add("Campo: " & _
oDataColumn.ColumnName & " --- " & _
"Tipo: " & oDataColumn.DataType.Name)
Next
End Sub
La Figura muestra el ListBox relleno con el esquema del DataSet tras haber pulsado el
botón del formulario.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 539


Obtención del esquema de un DataSet.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 540


Adendum

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 541


PASOS PARA CREAR UN ORIGEN DE DATOS TIPO SDF EN VISUAL
BASIC.NET
1.-Ventana Explorador de proyecto – boton derecho-> agregar->componente

Paso 2.-
Seleccionar base de datos local, si desea cambiar el nombre de la base local puede hacerlo
En este momento, al base local se guardara donde está ubicado la aplicación.

Paso 3.- Seleccionar conjunto de datos -> siguiente

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 542


Paso 4.-
La pantalla envía un mensaje es nueva y que no contiene objetos, por lo tanto solo crea “el
cascaron” de la base de datos, finalizar

Ahora crearemos las tablas que usaremos en la aplicación:


En la barra de menú seleccione ver-> exploradores de servidores, seleccione la base de
datos
De trabajo, seleccione tabla botón derecho-> crear tabla

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 543


Aparecerá algo asi:

Llena los campos nombre de la tabla, nombre de columna, tipo de dato longitud, etc
Por cada uno de los campos de la tabla de trabajo

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 544


Para terminar le da aceptar y listo, ahora solo tenemos que introducir datos a la tabla.
Se va explorador de servidores, se ubica en la tabla, botón derecho-> mostrar datos de tabla

Si la tabla contiene registros estos se verán:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 545


Si la tabla no tiene registros se verá así:

Entonces procedemos agregar registros…


Ahora procederemos a agregar nuestra tabla en la aplicación:
Barra de menú-> orígenes de datos-> agregar nuevo origen de datos

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 546


Seleccionamos la tabla y la arrastramos al form de trabajo,

Esto crea automáticamente un datagridview con los registros de la tabla y una barra de
navegación de los mismos, observe los componentes que se agregan por defecto a la
aplicación.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 547


En la corrida se miraría asi:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 548


Acceso a datos *.mdf con Visual Basic.net

REQUISITOS A TENER INSTALADO EN SU COMPUTADOR:

Vamos a trabajar por pasos el primero paso por supuesto es abrir VISUAL BASIC.NET.

Justo en esa imagen pueden ver como yo estoy agregando un nuevo proyecto seleccionen
Aplicacion de Windows Form y le colocan un nombre en mi caso yo le coloque
“Accesoadatos” ustedes le pueden colocar el nombre que quieran

Ya al tener este paso cumplido vamos a observar que no queda una pantalla donde diseñar
nuestro sistema con una pantalla principal llamada Form1:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 549


Vamos a ir al Explorador de soluciones que es donde se van a encontrar todos los elementos
de tu proyecto de programación para abrir el explorador de soluciones lo puedes encontrar
del lado derecho o si no esta activo puedes ir al MENU ver y activas la que dice Explorador
de Objetos. A lo que lo tengan activo van a presionar click derecho sobre el nombre de su
solución en mi caso fue “Accesoadatos” (presiono click derecho) y selecciono Agregar
Nuevo elemento (Add New ítem).

En la lista que aparece para agregar nuevos elementos a nuestro proyecto debemos
seleccionar el objeto Base de datos basada en servicio para poder tener una base de datos
donde almacenar y funcionar bajo windows la otra opción muy parecida se utiliza para base
de datos para aplicaciones Móviles.. por eso no seleccionamos bases de datos local, debes
cuidar que la extensión del archivo que agregas a la solución es .MDF así estarás mas seguro
cambia el nombre de la base de datos a tu gusto en mi caso le coloque BDejemplo.mdf aquí
pueden ver el ejemplo en pantalla:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 550


Al dar click al botón agregar va a realizar unos procesos y va a aparecer un asistente para
base de datos al cual debes darle aceptar de lo contrario ese asistente creara un Dataset
Tipado propio y lo ideal es que tu sepas como agregarlo manualmente.

Una vez que ya nuestra base de datos esta creada procedemos a darle desde el explorador
de objetos dos veces click a la base de datos para poder visualizar del lado izquierdo el
Explorador de base de datos muy importante para crear nuestras tablas y procedimientos
te fijaras que hay una parte que dice TABLAS presionando click derecho y seleccionar
agregar nueva Tabla lo puedes ver en la siguiente imagen:

Al presionar podemos agregar los campos que tendrá nuestra tabla para hacerlo mas
sencillo vamos a agrega solo tres campos de manera que expliquemos hoy como agregar
un elemento y como mostrar los datos de la tabla. Los Campos será Cedula que sera un
campo clave, nombre y apellido. Ninguno va a permitir valores nulo la cedula será de tipo
numérico y nombre y apellido nvarchar(50). Lo pueden ver en la imagen:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 551


Solo queda presionar salir y te pedirá que guardes la tabla con el nombre que tu quieras en
mi caso le coloque alumnos, ahora procedemos a agregar unos datos de ejemplo a nuestra
tabla asi como agregamos nueva tabla: le van a dar click derecho al nombre de la tabla que
acaban de agregar y le dan a la Opcion Mostrar datos de tabla hay podrán agregar algunos
datos de ejemplo.

Solo queda presionar guardar y ahora es hora de diseñar el formulario para poder dar el
ejemplo solamente se usaran los siguientes controles: Un Datagridview para mostrar los
datos tres Botones uno para guardar otro para cargar los datos y otro para salir del sistema,
tres textbox para agregar los tres datos de la base de datos de ejemplo y tres controles
label para identificar a que dato corresponde cada textbox. Para ello debemos hacer uso
del cuadro de herramientas para agregar los controles al formulario se puede ver del lado
izquierdo y si no esta activo pueden ir al pestaña menú Ver y activar Cuadro de
herramientas.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 552


Aquí como puede observar ya he agregado los controles, les recuerdo que .NET es
Orientado a objetos y todo objeto tiene sus propiedades estados y métodos., por ellos es
importante saber con que propiedades vamos a trabajar la mayoría de los controles
encontramos en sus propiedades valga la redundancia la propiedad TEXT y la propiedad
NAME, text en el nombre que se va a visualizar y NAME el nombre como se reconocerá
programáticamente ese objeto las propiedades las podemos observar del lado Derecho al
momento de seleccionar uno o varios objetos si no salen puedes ir al menu ver y activas
ventana propiedades.

si pueden observar modifique la propiedad TEXT de los label para identificar que dato va en
cada textbox y los nombres de cada botón ahora vienen haciendo a la propiedad name que
no va a producir ningún cambio solo lo verán mas adelante como ejemplo deben saber que

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 553


cada control tiene un nombre clave para saber que tipo es por ejemplo los Label llevan LBL
los textbox llevan TXT y los botones CMD si quiero identificar los tres botones y los tres
textbox programáticamente modifico la propiedad name de cada uno y usaría TXTcedula,
TXTnombre. TXTapellido, CMDguardar, CMDsalir, CMDcargar y aun falta el datagrid yo
personalmente le coloco DGW es decir en este caso le colocaría DGWdatos. de esta manera
estarán organizados los nombres programáticamente y mas adelante verán la importancia
de hacer esto.

Ahora toca agregar un sistemas de tipos a nuestro proyecto al igual que agregamos la base
de datos vamos a presionar en el Explorador de soluciones click derecho sobre el nombre
de nuestro proyecto y agregar un nuevo elemento, es este caso debemos agregar un
conjunto de datos que tiene extensión .XSD por nombre yo le coloque DSprueba ustedes le
colocar el nombre que ustedes quieran una vez que agregamos su nombre le damos
agregar:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 554


Una vez que agregamos aparecerá una pantalla de fondo celeste con el siguiente mensaje:
Utilice el diseñador de base de datos para trabajar con un conjunto de tablas con tipo
Solo queda arrastrar la tabla que creamos a ese diseñador de datos con tipo:

Una vez agregada nos aparecerá la tabla con sus campos y en la parte de abajo métodos
para buscar esos datos donde a este vamos a agregar dos consultas de las cuales una ya la
tiene por defecto y la otra es para guardar los datos es decir vamos a usar sentencias
TRANSAC SQL para insert y para select. quiza te sea un poco extraño esto pero poco a poco
te vas acostumbrando solo es cosa de practicar querer aprender y no tenerle miedo , el
método que se agrega por defecto se llama FILL,Getdata a este método le vamos presionar
click derecho y le damos a la opcion agregar consulta,

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 555


Al presionar esta opción tendremos un asistente que nos ayudara con esto del transact SQL
que ya les voy a explicar.. la primera opción que sale es que si queremos crear un sentencia
SQL, un procedimiento almacenado y un procedimiento almacenado ya existente por
experiencia es mejor usar procedimientos almacenados los invito a que investigues sobre
ellos son recomendados en las buenas practicas de programación y acceso a datos en si
todos vamos a elegir la segunda opción y nos saldrá entonces la siguiente pantalla:

donde podrán ver que la primera opción es un select que devuelve una fila en este caso es
si quieres el valor de una o varias filas dependiendo del dato que desees por ejemplo dame
el dato donde la cedula sea tal, en este ejemplo solo obtendrás un resultado por que es
imposible hayan dos personas con el mismo numero de cedula pero si fuera apellido si es
posible tener mas de dos resultados esta es la que usaremos pero ya por defecto ya esta
realizado, en el segundo caso es un Select que devuelve un solo valor: en esta opción
podrán obtener resultados como cuantos registros tienen en su tabla hacer una suma de
una columna que contenga valores como sueldos entre otras esta no la usaremos en este
caso.

El tercer caso es un UPDATE se utiliza para actualizar datos de un registro que ya existe es
decir la función MODIFICAR, para el cuarto se trata de un DELETE lógicamente se utiliza
para eliminar registros de la tabla y por ultimo un INSERT es lo mismo que guardar datos y
es el que utilizaremos para darle función al botón guardar así que este es el que vamos a
seleccionar y visualizaras luego la siguiente pantalla:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 556


Esta es la consulta o TRANSAC SQL si no estás de acuerdo con lo que el asistente hizo puedes
modificarlo y personalizarlo presionando GENERADOR DE CONSULTAS. En otra ocasión
explico más profundamente esta parte al presionar generador de consulta le dan aceptar
para mejorar esa consulta sql que debe quedar de esta forma para los datos que trabajo y
nombre de la tabla

INSERT INTO Alumnos


(Cedula, Nombre, Apellido)
VALUES (@Cedula,@Nombre,@Apellido)

Si aparece algo mas luego de presionar aceptar sobre el generador de consulta bórrenlo y
deje solo esto que les coloque normalmente se agrega algo como esto

SELECT Cedula, Nombre, Apellido FROM Alumnos WHERE (Cedula = @Cedula)

Y se utiliza para que luego de agregar los datos llamarlos de una vez pero en este caso no lo
vamos a usar.

Luego de presionar en siguiente solo les pedirá el nombre del procedimiento almacenado y
el nombre de la función ya listo ya tenemos nuestro diseñador de dataset con dos funciones
una que se agregó por defecto llama da fill,GET y la segunda agregada por nosotros para
guardar datos llamada en mi caso le coloque como nombre INSERALUM ustedes pueden
colocarle el que quiera pero este nombre lo utilizaremos más adelante. Así nos debe quedar
nuestro dataset en el diseñador.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 557


Ahora toca agregar código a los botones lo primero que haremos es agregar código al botón
guardar le daremos dos veces click para ir al evento click de ese botón así a lo que
presionemos click se ejecutara el código que le coloquemos, Debemos aprender como
llamar a los datos de un Dataset Tipados Básicamente hay que hacer dos instanciar de
nuevo programación orientada a objetos estos datos estas almacenados en unas clases que
crea visual studio debemos llamar a esas clases para que nos permita trabajar con los
métodos insertalum y FILL para ellos se agrega el siguiente código:

Dim ds As New DSprueba.AlumnosDataTable


Dim dt As NewDSpruebaTableAdapters.AlumnosTableAdapter

Quiza lo puedan ver mejor desde la imagen:

se declararon dos variables ds y dt dt es la que usaremos para acceder al método inseralumn


agregando el código

dt.insertalum(TXTcedula.Text, TXTnombre.Text, TXTapellido.Text)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 558


en la imagen notamos como a agregar el código dt.inseralum( nos ayuda a ver que valores
debemos agregar pidiéndonos cedula, nombre y apellido, hay es donde se justifica el por
que agregar nombre programático a cada text box ya con solo hacer esto el botón guardar
funciona vamos a agrega el método fill al botón cargar debemos hacer lo mismo si
queremos lo que hacemos es sacar las primeras dos líneas de código para que funcione
generalmente para cualquier botón así solo agregamos el siguiente código presionando dos
veces click en el botón cargar.

dt.Fill(ds.alumnos)

DGWdatos.DataSource = ds.alumnos

De esta manera al presionar sobre el botón cargar el datagrid se llenara de los datos de la
tabla alumnos solo falta el botón salir presiona dos veces click y escribe el código

End

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 559


USO DEL CONTROL DATAGRIDVIEW VB.NET

Caracteristicas:
Permite visualizar datos en una cuadricula personalizable.
Manipulación (operaciones)
Modificación (cambiar, guardar) de datos procedentes de una base de datos (tablas) tales
como consultas vistas etc.
También datos ingresados en tiempo de ejecución, o por el código directamente.
En este caso les presentamos en tiempo de ejecución.

PROPIEDADES MÁS USADOS DEL CONTROL:


Las propiedades de este control aparecen como los demás en la ventana de propiedades.
Las propiedades de las columnas son diferentes a las del control, a ellas se tiene acceso por
medio de la flecha desplegable que aparece en la parte derecha de la cuadricula, de la cual se
despliega un cuadro con las opciones de AGREGAR COLUMNAS y EDITAR
COLUMNAS

AGREGAR COLUMNAS: Nos permite adicionar la cantidad de columnas que se


considere necesarias para el proyecto. La propiedad NAME de las columnas aparece por
defecto como culmn1, column2, column3…, columnn etc.
EDITAR COLUMNAS: Nos permite agregar título a cada una de las columnas.
PROPIEDAD HEADER TEXT= texto, si no se requiere titulo en la columna se pone la
propiedad en blanco.

EJEMPLO 1: CALCULAR SUMA, RESTA MULTIPLICACION Y PROMEDIO

Para este ejemplo crear un formulario llamado: operaciones DataGridView, y agregar los
siguientes controles:
Dos buttons. 1)- Propiedad texto = AGREGAR VALORES A LA MATRIZ.
2)-Propiedad Texto = EJECUTAR OPERACIONES
Dos textbox con la propiedad name = por defecto.
Dos Label, 1)-Name = por defecto, texto = SUMA TOTAL.
2)- Name=por defecto, texto = PROMEDIO TOTAL.

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 560


Un DataGridView con la propiedad name = por defecto.

Haz click aquí para cambiar el nombre de las columnas y el tamaño…..


Diseño autosizemode esto te dara el tamaño de la columnaAgregar al DataGridView 10
columnas de las cuales su nombre serán por defecto y su texto = así
Header text =
Header text=
Header text =
Header text =
Header text =
Header text =
Header text = SUMA
Header text = PROMEDIO
Header text = RESTA
Header text = MULTIPLICACION

Haz click aquí para cambiar el nombre de las columnas y el tamaño…..


Diseño autosizemode esto te dara el tamaño de la columna

DISEÑO DE FORMULARIO:

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 561


CODIGO:
Public Class Form1
'Declaracion de la matriz'
Dim M(5, 5) As Integer
Dim sumatotal As Integer
Dim promediototal As Double

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As -


System.EventArgs) Handles MyBase.Load
'Declaracion de la matriz contenida en el datagridview1'
‘ asignamos los valores de 0 a cada campo
DataGridView1.RowCount = 6
For i As Integer = 0 To 5
For j As Integer = 0 To 5
M(i, j) = 0 ‘ primero a la matriz que declaramos
DataGridView1.Item(i, j).Value = M(i, j) ‘ Igual al data gridView1
Next
Next
End Sub

‘LLENAMOS LA MATRIZ DE FORMA INTERACTIVAS (LO HACE EL USUARIO)'


Private Sub btnAgregar_Click(ByVal sender As System.Object, ByVal e As -
System.EventArgs) Handles btnagregar.Click
Try
For i As Integer = 0 To 5
For j As Integer = 0 To 5
M(i, j) = CInt(InputBox("digite el valor"))
DataGridView1.Item(j, i).Value = M(i, j)
Next
Next
MsgBox("llena")
Catch ex As Exception
MsgBox(ex.Message)

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 562


End Try
End Sub
‘ CON LOS DATOS OBTENIDOS EJECUTAMOS LAS OPERACIONES
Private Sub btnejecutar_Click(ByVal sender As System.Object, ByVal e As -
System.EventArgs) Handles btnejecutar.Click
Try
'suma fila 0'
Dim suma = 0
For i = 0 To 5
suma = suma + M(0, i)
Next
DataGridView1.Item(6, 0).Value = suma
'promedio fila 0'
Dim promedio As Double
promedio = suma / 6
DataGridView1.Item(7, 0).Value = promedio
'resta fila 0'
Dim resta As Integer
resta = suma - promedio
DataGridView1.Item(8, 0).Value = resta
'multiplicacion fila 0'
Dim multiplicacion As Integer
multiplicacion = promedio * resta
DataGridView1.Item(9, 0).Value = multiplicacion
'suma fila1'
Dim suma1 = 0
For i = 0 To 5
suma1 = suma1 + M(1, i)
Next
DataGridView1.Item(6, 1).Value = suma1
'promedio fila 1'
Dim promedio1 As Double
promedio1 = suma1 / 6
DataGridView1.Item(7, 1).Value = promedio1
'resta fila 1'
Dim resta1 As Integer
resta1 = suma1 - promedio1
DataGridView1.Item(8, 1).Value = resta1
'multiplicacion fila 1
Dim multiplicacion1 As Integer
multiplicacion1 = promedio1 * resta1
DataGridView1.Item(9, 1).Value = multiplicacion1
'suma fila 2'
Dim suma2 = 0
For i = 0 To 5
suma2 = suma2 + M(2, i)
Next

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 563


DataGridView1.Item(6, 2).Value = suma2
'promedio fila 2'
Dim promedio2 As Double
promedio2 = suma2 / 6
DataGridView1.Item(7, 2).Value = promedio2
'resta fila 2'
Dim resta2 As Integer
resta2 = suma2 - promedio2
DataGridView1.Item(8, 2).Value = resta2
'multiplicacion fila 2'
Dim multiplicacion2 As Integer
multiplicacion2 = promedio2 * resta2
DataGridView1.Item(9, 2).Value = multiplicacion2
'suma fila 3'
Dim suma3 = 0
For i = 0 To 5
suma3 = suma3 + M(3, i)
Next
DataGridView1.Item(6, 3).Value = suma3
'promedio fila 3'
Dim promedio3 As Double
promedio3 = suma3 / 6
DataGridView1.Item(7, 3).Value = promedio3
'resta fila 3'
Dim resta3 As Integer
resta3 = suma3 - promedio3
DataGridView1.Item(8, 3).Value = resta3
'multiplicacion fila 3'
Dim multiplicacion3 As Integer
multiplicacion3 = promedio3 * resta3
DataGridView1.Item(9, 3).Value = multiplicacion3
'suma fila 4'
Dim suma4 = 0
For i = 0 To 5
suma4 = suma4 + M(4, i)
Next
DataGridView1.Item(6, 4).Value = suma4
'promedio fila 4'
Dim promedio4 As Double
promedio4 = suma4 / 6
DataGridView1.Item(7, 4).Value = promedio4
'resta fila 4'
Dim resta4 As Integer
resta4 = suma4 - promedio4
DataGridView1.Item(8, 4).Value = resta4
'multiplicacion fila 4'
Dim multiplicacion4 As Integer

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 564


multiplicacion4 = promedio4 * resta4
DataGridView1.Item(9, 4).Value = multiplicacion4
'suma fila 5'
Dim suma5 = 0
For i = 0 To 5
suma5 = suma5 + M(5, i)
Next
DataGridView1.Item(6, 5).Value = suma5
'promedio fila 5'
Dim promedio5 As Double
promedio5 = suma5 / 6
DataGridView1.Item(7, 5).Value = promedio5
'resta fila 5'
Dim resta5 As Integer
resta5 = suma5 - promedio5
DataGridView1.Item(8, 5).Value = resta5
'multiplicacion fila 5'
Dim multiplicacion5 As Integer
multiplicacion5 = promedio5 * resta5
DataGridView1.Item(9, 5).Value = multiplicacion5
'sumatoria de la columna de SUMA'
sumatotal = Val(suma + suma1 + suma2 + suma3 + suma4 + suma5)
'guardar en textbox la sumatoria total'
TextBox1.Text = sumatotal
'Promedio total de la columna promedio'
promediototal = Val(promedio + promedio1 + promedio2 + promedio3 + promedio4 +
promedio5)
'guardar en textbox el promedio total'
TextBox2.Text = promediototal / 6
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
End Class

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 565


Buscar fila en DataGridView

Buscar un registro o fila en un control de tipo DataGridView

Código de ejemplo que usa el método Find del componente BindingSource para buscar un
registro en un campo específico en una tabla

formulario

Controles

 Un control DataGridView llamado DataGridView1


 Un control Button llamado Button1 ( botón para buscar )
 Un control textBox llamado textBox1 ( para ingresar el dato )
 Indicar el campo por el cual buscar ( Primer parámetro del método Find)
 Establecer la cadena de conexión a utilizar

Código fuente

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 566


Option Explicit On
Option Strict On
Imports System.Data
Imports System.Data.SqlClient
Public Class Form1
' ConnectionString para SQL server EXPRESS
Private Const cs As String = "Data Source=(local)\SQLEXPRESS;" & _
"Integrated Security=True;" & _
"Initial Catalog=la_base_de_datos"
'Declarar un BindingSource
Private BindingSource1 As Windows.Forms.BindingSource = New BindingSource
Private Sub Form1_FormClosed( _
ByVal sender As Object, _
ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
BindingSource1.Dispose()
End Sub
Private Sub Form1_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load

Button1.Text = "Buscar fila"


Try
' Declarar la conexión y abrir
Using cn As SqlConnection = New SqlConnection(cs)
cn.Open()
' Crear un DataAdapter y pasarle el comando para traer los registros
Dim da As New SqlDataAdapter("SELECT * FROM la_tabla", cn)
' DataTable
Dim dt As New DataTable
' llenar el DataTable
da.Fill(dt)
' enlazar el DataTable al BindingSource
BindingSource1.DataSource = dt
' propiedades para el DataGridview
'''''''''''''''''''''''''''''''''''''''
With DataGridView1
' opcional: Sin selección múltiple
.MultiSelect = False
' seleccioanr fila completa al hacer clic en un registro
.SelectionMode = DataGridViewSelectionMode.FullRowSelect
' enlazar los controles

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 567


.DataSource = BindingSource1.DataSource
End With
End Using
' errores
Catch ex As Exception
MsgBox(ex.Message.ToString)
End Try
End Sub

' Función que retorna el índice de la fila


'' ''''''''''''''''''''''''''''''''''''''''''''''''''''
Function Buscar( _
ByVal Columna As String, _
ByVal texto As String, _
ByVal BindingSource As BindingSource) As Integer

Try
' si está vacio salir y no retornar nada
If BindingSource1.DataSource Is Nothing Then
Return -1
End If
' Ejecutar el método Find pasándole los datos
Dim fila As Integer = BindingSource.Find(Columna.Trim, texto)
' Mover el cursor a la fila obtenida
BindingSource.Position = fila
' retornar el valor
Return fila
' errores
Catch ex As Exception
MsgBox(ex.Message.ToString, MsgBoxStyle.Critical)
End Try
' no retornar nada
Return -1
End Function

' Botón para buscar en el DataGridView


Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
' Pasar el nombre del campo por el cual buscar ,
' el dato, y el BindingSource enlazado al DataGridView

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 568


'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim ret As Integer = Buscar( _
"Nombre", _
TextBox1.Text.Trim, _
BindingSource1)
' si no se encontró ....
If ret = -1 Then
' mostrar un mensaje
MsgBox("No se encontró la fila", MsgBoxStyle.Critical)
Else
With DataGridView1
' volver a enlazar
.DataSource = BindingSource1
' Pasarle el índice para Visualizar la fila al comienzo de la grilla
.FirstDisplayedScrollingRowIndex = ret
End With
End If
End Sub
End Class

Buscar usando el método find de la propiedad DefaultView

Código similar al anterior , pero que usa el método Find de la propiedad Defaultview de un
Dataset accediendo a la base de datos mediante OLEDB

( Button1 , dataGridView1 y TextBox1)

Nota: indicar la cadena de conexión, el comando sql en el oledbdataAdapter y también el


nombre del campo por el cual buscar, en la propiedad Sort

Option Explicit On

' Espacio de nombres para para acceder al proveedor OleDb


Imports system.Data.OleDb
Public Class Form1
' declaración del ConnectionString
Private Const cadena_conexion As String = "Indicar la cadena"
' declaración del dataset
Private oledb_dataset As DataSet
Private Sub Form1_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 569


Button1.Text = "Buscar"
TextBox1.Text = String.Empty
'Configurarar propiedades para el DataGridView
With DataGridView1
.MultiSelect = False
.SelectionMode = DataGridViewSelectionMode.FullRowSelect
End With
Try
' Inicializar nueva conexión OLEDB y abrirla
Using cn As New OleDbConnection(cadena_conexion)
cn.Open()
' Inicializar nuevo adaptador de datos OleDb
Dim da As New OleDbDataAdapter("Select * From una Tabla", cn)
' Crear y cargar el DataSet
oledb_dataset = New DataSet
da.Fill(oledb_dataset, "Mi Tabla")
With oledb_dataset.Tables("Mi Tabla")
' Indicar en la propiedad Sort el campo por el cual buscar
.DefaultView.Sort = "Clientes"
' asignar el origen de datos a la grilla
DataGridView1.DataSource = .DefaultView
End With
End Using

Catch ex As Exception
MsgBox(ex.Message.ToString)
Finally
Me.Cursor = Cursors.Default
End Try
End Sub

Private Sub Button1_Click( _


ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
' buscar y retornar el índice de la fila encontrada
Dim fila As Integer = oledb_dataset.Tables("Mi tabla").DefaultView.Find(Text
Box1.Text)
' si el índice es -1 no se encontró
If fila <> -1 Then

With DataGridView1

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 570


' Establecer el índice de la primera fila del DataGridview
' para visualziarlo arriba de todo
.FirstDisplayedScrollingRowIndex = fila
' asignar la celda al CurrentCell para seleccionarla
.CurrentCell = .Rows(fila).Cells(0)
' seleccionar el control
.Select()
'mostrar el índice en el caption del formulario
Me.Text = "índice de la fila actual : " & .CurrentCell.RowIndex.ToString
End With
Else
' No se encontró
MsgBox("No se encontró el elemento en el DataGridView")
End If
End Sub
End Class

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 571


Ejemplo de programa de uso de clase en Visual Basic NET

Ejemplo Calcular el salario de los empleados de una tienda, información a sacar por pantalla
Nombre del empleado y Salario semanal, datos conocidos: nombre, número de horas trabajadas
y pago por hora del empleado

El salario se calcula de la manera siguiente:

Si el número de horas trabajadas es mayor que 40, el excedente de 40 se paga al doble de la


cuota por hora, en caso de no ser mayor que 40 se paga a la cuota por hora normal.

Realicemos la solución de acuerdo al modelo-vista-controlador

Algoritmo Calcular Salario de un empleado

Public Class Empleado


Algoritmo Calcular Salario de un empleado
'Declaraciones de Datos
Private NombreEmpleado As String
Clase Empleado
Private HorasTrabajadas As Integer
1.- Declaraciones
Private PagoHora As Double
Datos
Private Salario As Double
NombreEmpleado: Cadena
HorasTrabajadas: Entero
Public ReadOnly Property obtenerNombre()
PagoHora: Real
As String
Salario: Real
' bloque Get obtener para devolver el
valor de la propiedad
2.- Metodo EstablecerNombre( nom: cadena)
Get
NombreEmpleado = nom
Return NombreEmpleado
Fin Metodo EstablecerNombre
End Get
End Property
3.- Metodo Establecerhoras(horas: Entero)
HorasTrabajadas = horas
Public WriteOnly Property establecerNombre()
Fin Metodo EstablecerHoras
As String
' bloque Set (Establecer) para asignar
4.- Metodo EstablecerPago( pago: Real)
valor a la propiedad
PagoHora = pago
Set(ByVal Value As String)
Fin Metodo EstablecerPago
NombreEmpleado = Value
End Set
5.-Metodo CalcularSalario( )
End Property
If HorasTrabajadas<= 40 Then
Salario = HorasTrabajadas * PagoHora
Public ReadOnly Property obtenerHoras() As
Else
Integer
Salario= (40*PagoHora)+
' bloque Get para devolver el valor de la
(( HorasTrabajadas -40) *( PagoHora * 2))
propiedad
Endif
Get
Fin Metodo EstablecerNombre
Return HorasTrabajadas
End Get
6.- Metodo ObtenerNombre() : Cadena
End Property
Return NombreEmpleado
Fin Metodo ObtenerNombre
Public WriteOnly Property EstablecerHoras()
As Integer
7.- Metodo ObtenerSalario( ) : Real
' bloque Set para establecer valor a la
Return Salario
propiedad
Fin Metodo ObtenerSalario
Set(ByVal hora As Integer)
HorasTrabajadas = hora
Fin de clase empleado End Set
MSc. Ing. Jorge Prado D. Docente: EndNacional
Universidad Property de Ingeniería 572
Diseño en Visual Basic
Public WriteOnly Property EstablecerPago() As
Double
' bloque Get para devolver el valor de la
propiedad
Set(ByVal value As Double)
PagoHora = value
End Set
End Property

Public ReadOnly Property ObtenerPagoHora()


As Double
' bloque Set para estsblecer el valor a la
propiedad
Get
Return PagoHora
End Get
End Property

Public Sub CalcularSalario()


' en este método calculamos el salario del
empleado
If HorasTrabajadas <= 40 Then
Salario = HorasTrabajadas * PagoHora
Else
Salario = (40 * PagoHora) +
((HorasTrabajadas - 40) * (PagoHora * 2))
End If
End Sub

Public ReadOnly Property ObtenerSalario()


As Double
Get
Return Salario
End Get
End Property
End Class

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 573


MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 574
Algoritmo y programa OO usando selección múltiple en Visual Basic NET

Ejercicio: Elaborar un algoritmo que dado un numero del 1 al 7, el programa imprima


por pantalla “Domingo ”,si es 1, “Lunes”, si es 2… “Sábado”, si es 7.

Solución:

Algoritmo PresentaDia de la semana Public Class PresentaDia


Clase PresentaDia REM Declaraciones de Datos
Declaraciones Private INumDia As Integer
Datos Public SNombreDia As String
NumDia : Entero ' Metodo obtener nombreDia de solo
NombreDia : Cadena escritura
ReadOnly Property Nombre() As String
Metodo EstablecerNDia( num: Entero) Get
NumDia = Num Nombre = SNombreDia
Fin de método EstablecerDia End Get
Metodo CalcularNombredia() End Property
Swith NumDia
1: Nombredia = “Domingo” 'Metodo establecer Numero del Dia
2: Nombredia = “Lunes” solo lectura
3: Nombredia = “Martes” WriteOnly Property Dia() As Integer
4: Nombredia = “Miércoles” Set(ByVal value As Integer)
5: Nombredia = “Jueves” INumDia = value
6: Nombredia = “Viernes” End Set
7: Nombredia = “Sábado” End Property
DEFAULT
NombreDia = “No está en el rango de 1 a 7 “ ' Metodo CalcularNombredia()
ENDSWITCH Public Sub CalcularDia()
Fin Metodo CalcularNombreDia Select Case (INumDia)
Metodo ObtenerNombreDia() : Cadena Case 1
Return NombreDia SNombreDia = "Domingo"
Fin Metodo ObtenerDia Case 2
SNombreDia = "Lunes"
Fin clase PresentaDia Case 3
SNombreDia = "Martes"
Case 4
SNombreDia = "Miercoles"
Case 5
SNombreDia = "Jueves"
Case 6
SNombreDia = "Viernes"
Case 7
SNombreDia = "Sabado"
Case Else
SNombreDia = "No existe ese dia"
End Select
End Sub
End Class
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 575
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 576
Algoritmo y programa OO usando Estructura de repetición DO…WHILE en
Visual Basic NET

Ejemplo: Elaborar un algoritmo para calcular e imprimir el sueldo de varios empleado


de una empresa.

Datos disponibles: Nombre, Horas Trabajadas, Cuota por Hora


Proceso: Sueldo = Horas Trabajadas * cuota por Hora
Imprimir: Nombre, Sueldo.

Solución:

Clase Empleado Public Class Empleado


Declaraciones Private NombreE As String
Datos Public Property Nombre() As
NombreE : Cadena String
HorasT : Entero Get
PagoH : Real Nombre = NombreE
Sueldo : Real End Get
Set(ByVal valor As String)
Metodo EstablecerNombreE(nom : Cadena) NombreE = valor
NombreE = nom End Set
Fin método EstablecerNombreE End Property

Metodo EstablecerHorasT (Horas : Enterol) Private HorasT As Double


HorasT = Horas Public Property Horas() As String
Fin de método EstablecerHorasT. Get
Horas = HorasT
Metodo EstablecerPagoH( Pago : Real) End Get
PagoH = Pago Set(ByVal valor As String)
Fin Metodo EstablecerPagoH HorasT = valor
End Set
End Property
Metodo CacularSueldo()
Sueldo = HorasT * PagoH
Private PagoH As Double
Fin método CalcularSueldo
Public Property Pago() As String
Get
Metodo ObtenerNombreE(): Cadena
Pago = PagoH
Return NombreE
End Get
Fin Metoddo ObtenerNombreE
Set(ByVal valor As String)
PagoH = valor
Metodo ObtenerSueldo() : Real End Set
Return Sueldo End Property
MSc.FinIng. JorgeObtenerSueldo
método Prado D. Docente: Universidad Nacional de Ingeniería 577
Private Sueldo As Double
Fin Clase Empleado ReadOnly Property Salario() As
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 578
Algoritmo y programa OO usando arreglos unidimensionales en Visual Basic
NET

Ejercicio:

Se conoce el número de unidades producidas por un obrero en cada uno de los 30 días
del mes. Elaborar un algoritmo que permita leer la producción de cada uno de los 30 días
y luego los visualice.

Clase Obrero
1.- Declaraciones
Datos
Producción: Arreglo[30] : Entero
2.- Método establecerProduccion(pro[]:
Entero)
Producción = pro
Fin método establecerProduccion
3.- Metodo obtenerProduccion():
Arreglo[] Entero
Return producción
Fin método obtenerProduccion
Fin Clase Obrero

Clase Ejecutaobrero
1.- Metodo principal
Declaraciones
MSc. Ing.Variables
Jorge Prado D. Docente: Universidad Nacional de Ingeniería 579
Prod, prod2:arreglo[30] Entero
I : Entero
Algoritmo y programa OO usando herencia en Visual Basic NET

Ejercicio:
En cierta empresa se tienen empleados; los empleados se dividen en dos tipos, empleados
por hora, a los que se les paga de acuerdo con el número de horas trabajadas y a una
cuota por hora. El otro tipo son los empleados asalariados, a quienes se les paga de
acuerdo a un sueldo fijo mensual.

Clase empleado
Declaraciones: Datos
# nombreEmpleado : cadena
# deptoEmple : cadena
# puestoTrabajo: cadena

Método establecerNombre(nom : cadena)


nombreEmpleado = nom
Fin método establecerNombre

Método establecerDepto(dep: cadena)


depatoEmple = dep
Fin de método establecerDepto

Método establecerPuesto(pues : cadena)


puestoTrabajo = pue
fin método establecerPuesto
MSc.Metodo
Ing. Jorge Prado D.
obtenerNombre() Docente: Universidad Nacional de Ingeniería
: cadena 580
Return nombreEmpleado
Fin método obtenerNombre
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 581
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 582
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 583
MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 584
Algoritmo y programa OO usando polimorfismo en Visual Basic NET.

Ejercicio: El mismo ejercicio anterior, pero utilizando el concepto de polimorfismo

Clase abstracta Empleado2


Declaraciones
Datos
# nombreEmpleado: Cadena
# deptoEmple : Cadena
# puestoTrabajo : Cadena
# SueldoQna: Real
Metodo establecerNombre(nom: Cadena)
nombreEmpleado = nom
Fin método establecerNombre

Método establecerDepto(dep: cadena)


deptoEmple = dep
Fin de método establecerDepto

Método establecerPuesto(pues : cadena)


puestoTrabajo = pue
fin método establecerPuesto

Metodo abstracto calcularSueldoQna()

Metodo obtenerNombre() : cadena


Return nombreEmpleado
Fin método obtenerNombre

Método obtenerPuesto() : cadena


Return puestoTrabajo
Fin método obtenerPuesto

Método obtenerDpto() : cadena


Return deptoEmple
Fin método obtenerDpto

Método obtenerSueldoQna() : Real


Return SueldoQna
Fin método obtenerDpto

Fin clase Empleado2

MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 585


MSc. Ing. Jorge Prado D. Docente: Universidad Nacional de Ingeniería 586

También podría gustarte