Documentos de Académico
Documentos de Profesional
Documentos de Cultura
net/publication/287646094
CITATIONS READS
0 4,522
1 author:
SEE PROFILE
Some of the authors of this publication are also working on these related projects:
Development of statistical tools for mobile devices. Fourth Stage. View project
All content following this page was uploaded by Hector Antonio Villa-Martinez on 21 December 2015.
Hay muchos libros sobre Java, los hay para principiantes y para avanzados, la mayoría
están en inglés y los pocos en español no son fáciles de encontrar y menos a buen precio.
En general estos libros tratan de abarcar mucho más material (y a veces sin la profundidad
necesaria) que el requerido para la asignatura.
Los apuntes están distribuidos de la siguiente forma: En el capítulo 1 se presenta una breve
historia y semblanza de Java y la forma de obtener el ambiente de desarrollo. El capítulo 2
es la única parte teórica en esta obra y muestra los principales conceptos de la
programación orientada a objetos. En el capítulo 3 se describe la sintaxis de Java. El
capítulo 4 muestra la forma de implementar en Java los conceptos de orientación a objetos
aprendidos en el capítulo 2. El capítulo 5 se ocupa de los applets que son programas en Java
que pueden correr en el Internet. El capítulo 6 presenta la forma de programar interfaces
gráficas de usuario usando una librería llamada AWT. Por último, el capítulo 7 muestra el
manejo básico de archivos en Java.
3
4
Índice
5
6.6 Aplicaciones con AWT 105
7 Archivos 109
7.1 Definición 109
7.2 Principales clases lectoras 109
7.3 Principales clases escritoras 113
7.4 Archivos de datos 118
7.5 Archivos remotos 121
6
Capítulo 1 Introducción al lenguaje Java
1.1 Historia
Java es un lenguaje de propósito general, orientado a objetos y concurrente[1]. Tuvo sus
inicios a principios de los 90s cuando Sun Microsystems decidió incursionar en el mercado
de la electrónica de consumo y desarrollar programas para controlar dispositivos
electrónicos y fundó una compañía subsidiaria llamada FirstPerson[2]. El primer proyecto
de FirstPerson fue desarrollar una interface interactiva para controlar los aparatos
eléctricos. Como parte de este objetivo un ingeniero de Sun llamado James Gosling definió
el lenguaje Oak basándose en la sintaxis de C++ pero eliminando algunas características,
como los apuntadores, que a su juicio hacen que la programación en C++ sea propensa a
errores y agregando algunas otras, como la recolección automática de basura, para hacer la
vida de los programadores más fácil.
FirstPerson no tuvo el éxito esperado y cerró en 1994. Parecía que Oak también estaba
condenado a desaparecer, sin embargo, Bill Joy cofundador de Sun, se dio cuenta que el
Internet podía ser usado para disputar el monopolio de software de Microsoft. Después de
un cambio de nombre, Java fue liberado en agosto de 1995.
1.2 Características
Java es neutral a la arquitectura. El compilador toma un archivo fuente y genera un archivo
objeto con códigos byte para una máquina virtual conocida como JVM (Java Virtual
Machine). El intérprete ejecuta los códigos byte del archivo objeto. Por lo tanto es portable
al nivel de código objeto.
Java es seguro. El chequeo de datos es muy estricto. Antes de que un código byte sea
ejecutado es revisado por la JVM para detectar accesos no autorizados a la memoria. El
manejo de la memoria es sencillo. Cada objeto se crea con el operador new y el
programador no es responsable de liberar la memoria. Cuando un objeto ya no se utiliza, el
recolector de basura automáticamente reclama ese espacio.
Java es distribuido. Tiene librerías para programación con TCP/IP (el protocolo de
comunicaciones standard de Internet).
Java es concurrente. Tiene librerías para hacer programas con múltiples hilos de ejecución
simultánea.
7
1.3 El ambiente de desarrollo
Java se presenta en 3 distribuciones: la edición empresarial (enterprise edition), la edición
standard (standard edition) y la edición micro (micro edition). La versión standard es la
versión original de Java. La edición empresarial es igual de poderosa que la versión
standard pero incluye librerías para programar aplicaciones grandes, distribuidas y con uso
intensivo de bases de datos. Por último, la edición micro esta orientada a la programación
de dispositivos con poca memoria, por ejemplo, teléfonos celulares o aparatos
electrodomésticos inteligentes, un poco siguiendo el objetivo inicial de Oak.
Para una introducción al lenguaje es suficiente trabajar con la edición standard. La versión
actual de Java es la 1.3, también conocida como Java 2, versión 1.3, edición standard (J2SE
1.3). Sun Microsystems regala el ambiente de desarrollo conocido como Java 2 SDK
(System Development Kit, kit de desarrollo de sistemas) o JDK (Java Development Kit, kit
de desarrollo de Java) para Windows, Solaris y Linux en la dirección
http://java.sun.com/j2se/1.3/
Para instalar el ambiente de desarrollo en Windows hay que bajar el archivo auto-extraíble
(extensión EXE) correspondiente al J2SE y el archivo comprimido (extensión ZIP) que
corresponde a la documentación. El archivo EXE se ejecuta y por default Java se instalará
en el directorio C:\jdk1.3. Luego hay que editar el archivo C:\Autoexec.bat y modificar las
variables de ambiente PATH y CLASSPATH agregándoles los caminos C:\jdk1.3\bin y
C:\jdk1.3\lib\classes.zip;C:\jdk1.3\lib\tools.jar respectivamente, por último el archivo
ZIP de la documentación se descomprime en el directorio C:\jdk1.3. El manual se puede
leer usando un navegador.
1.4.1 Definición
Java tiene dos formas de hacer un programa: como applet o como aplicación.
Un applet es un programa que está diseñado para ser invocado por una página HTML,
agregándole así funcionalidad. La característica principal de un applet es que, aunque reside
en la misma computadora que la página HTML que lo invoca, al ser accesada esta página
desde una computadora remota, el applet viaja a través de Internet y se ejecuta en el
navegador de la computadora que hizo el acceso. Por esta razón y como seguridad contra
programadores maliciosos, un applet no puede accesar ningún recurso de la computadora
donde se está ejecutando y tampoco puede comunicarse con ninguna otra computadora que
no sea la computadora donde estaba originalmente. Para correr applets no es necesario tener
instalado el JDK porque ya los principales navegadores comerciales (Internet Explorer y
Netscape) traen integrada una máquina virtual de Java.
8
Una aplicación es un programa que corre localmente en la computadora donde está
instalada. No tiene las restricciones de seguridad de los applets y tiene acceso a todos los
recursos locales pero para correr necesita que por lo menos el JRE esté instalado.
Hay que aclarar que fuera de la restricción que tienen los applets de estar incrustados en
una página HTML y de que no pueden accesar recursos en la computadora donde corren, la
programación de applets y aplicaciones es parecida y pueden usar cualquier librería del
lenguaje por igual.
Listado 1-1
public class HolaMundo {
9
Figura 1-1. Compilación y ejecución de una aplicación
Listado 1-2
import java.awt.Graphics;
import java.applet.*;
Paso 3. Editar un archivo de texto que se llame HolaMundo.html y copiar el código del
listado 1-3.
10
Listado 1-3
<HTML>
<HEAD>
<TITLE>Mi primer applet</TITLE>
</HEAD>
<BODY>
<P><H2>Este es mi primer applet</H2><P>
<APPLET CODE="HolaMundoApplet.class" WIDTH=250 HEIGHT=150>
</APPLET>
</BODY>
</HTML>
11
Referencias
[1] The Java Language Specification. Second Edition. James Gosling, Bill Joy, Guy Steele
and Gilad Bracha. Sun Microsystems Inc. 2000
12
Capítulo 2. Conceptos básicos de objetos
2.1 Introducción
Es un paradigma de programación donde los elementos de los lenguajes son objetos y
clases. Otros paradigmas de programación son:
1. Programación estructurada
• Los elementos son estructuras o bloques de instrucciones de decisión y repetición,
evitando el uso del goto.
• Uso de procedimientos y funciones.
• Principales exponentes: Pascal y C.
2. Programación funcional.
• Los elementos son funciones.
• Principales exponentes: LISP y Scheme.
3. Programación lógica.
• Los elementos son hechos y reglas para derivar nuevos hechos.
• Principal exponente: Prolog.
Java no es el único lenguaje orientado a objetos. Otros lenguajes que también manejan este
paradigma son C++, Smalltalk, Eiffel y varios más.
Un objeto es una entidad del mundo real. Por ejemplo, mi automóvil es un objeto. La
factura de mi computadora también es un objeto. Intuitivamente los objetos del mismo tipo
se pueden agrupar en clases. Mi automóvil y el automóvil del vecino son dos instancias de
algo que puede llamarse la clase de los automóviles. Se distinguen entre sí por que
posiblemente son de distinto modelo, color y fabricante y porque tienen placa, número de
serie y dueño diferente. Esas características que distinguen un objeto de otro se llaman
atributos. Las clases definen no solo los atributos que los objetos de esa clase pueden
tener, sino también su comportamiento esperado. Un automóvil puede estar prendido o
apagado, puede estar acelerando o frenando, o puede tener una velocidad x en este
momento. Todos los objetos de una misma clase tienen el mismo comportamiento y el
mismo número de atributos, sin embargo, cada objeto tendrá valores distintos para esos
atributos, lo que se conoce formalmente como estado del objeto y así podrá diferenciarse
de otros objetos de la misma clase. En resumen, una clase es un prototipo que define las
variables y los métodos comunes para los objetos de un mismo tipo.
Se pueden representar objetos del mundo real usando objetos de software. Puede que nos
interese representar un automóvil de la vida real como un objeto de software en un
programa que juegue a las carreras. Sin embargo, también se pueden usar objetos de
13
software para representar objetos abstractos. Por ejemplo, un evento es un objeto que se
utiliza para representar la acción que ocurre cuando un usuario oprime un botón dentro de
un programa que tenga interface gráfica.
Las clases promueven la reutilización del software. Los programadores pueden usar clases
creadas por otros programadores para crear objetos.
14
le conoce como ocultamiento de información. La encapsulación también fomenta la
modularidad, el código fuente de un objeto se puede desarrollar y mantener
independientemente del código fuente de otros objetos.
El último concepto del paradigma orientado a objetos que se revisará en este capítulo es la
herencia. La herencia es un mecanismo que permite definir clases en función de otras
clases. Por ejemplo, los pickups y los sedanes son tipos distintos de automóviles. En
lenguaje técnico se dice que los pickups y los sedanes son subclases de la clase automóvil.
De igual manera, se dice que la clase automóvil es la superclase de los pickups y sedanes.
Cada subclase hereda el estado de la superclase en forma de variables. Los pickups y los
sedanes comparten los estados, tienen número de serie, número de placa, color, etc.
También, cada subclase hereda los métodos de la superclase. Los pickups y los sedanes
comparten el comportamiento, pueden estar prendidos o apagados, tener una velocidad, etc.
15
16
Capítulo 3 Elementos del lenguaje
3.1 Introducción
En este capítulo vamos a revisar brevemente los elementos de la sintaxis de Java. El
recuento no intenta ser exhaustivo, se asume que el alumno ha tomado ya un curso de
programación en lenguaje C o C++.
Los tipos primitivos son los números enteros, números reales, booleanos y caracteres.
Los enteros siempre tienen signo. Hay cuatro tipos de enteros. La diferencia está en el
tamaño que ocupan y el rango que pueden guardar.
Los números reales pueden almacenar números con parte decimal. Hay dos tipos de
números reales. La diferencia es la cantidad de decimales que pueden representar.
El tipo boolean representa variables que pueden tener uno de dos valores: true o false.
Cada vez que se define una clase se está creando un nuevo tipo y se pueden declarar
variables de ese tipo. Por ejemplo, es posible declarar que una variable es de tipo String
porque en la librería standard ya está definida una clase llamada String.
17
3.2.3 Arreglos
En Java los arreglos se declaran sin tamaño. Para poder usarlos es necesario asignarles un
tamaño. Se puede lograr esto dándoles valores iniciales:
int vector[];
vector = new int[10];
o en un solo paso:
Los elementos de un arreglo se accesan mediante un índice que puede valer entre 0 y s – 1,
donde s es el tamaño del arreglo.
Usando cualquiera de las declaraciones anteriores, las siguientes instrucciones son válidas.
vector[1] = 20;
vector[2] = vector[0] + 10;
vector[0]++;
Los arreglos tienen asociada la variable length que indica el tamaño del arreglo. La forma
de accesarla es nombre-del-arreglo.length. En el caso del arreglo vector se puede usar así:
t = vector.length;
3.3 Comentarios
Si un comentario ocupa varias líneas se puede delimitar usando los símbolos /* y */. Si solo
se desea un comentario que ocupe una línea se usa el símbolo // para indicar al compilador
que ignore lo que sigue hasta el fin de línea.
3.4 Literales
El manejo de literales es igual que en C++. Las literales de string se delimitan entre
comillas dobles:
"hola mundo"
Si se desea que el string tenga comillas dobles es necesario poner el carácter de escape '\'.
18
Las literales de carácter se delimitan entre comillas sencillas: 'h', '$', '7'. Java maneja las
mismas literales para caracteres no imprimibles que C++, por ejemplo '\n' para el retorno de
carro y '\t' para el tabulador.
Las literales enteras se pueden especificar en base 10, por ejemplo 259, pero también se
pueden especificar en base 8 colocando un cero antes, por ejemplo 064 o en base 16
poniendo 0x, por ejemplo 0xA9.
Las literales reales se pueden escribir en formato normal, por ejemplo 2.943 o en formato
científico, por ejemplo 756.51E10 o 4.938E-2.
3.5 Operadores
Un operador es un símbolo especial que representa una operación y que se usa en una
expresión.
Java tiene los mismos operadores aritméticos que C++. El + para la suma, el – para la resta,
el * para la multiplicación, el '/' para la división y el '%' para el módulo.
Si todos los operandos en una expresión son enteros, la expresión regresa un entero. Basta
que uno de los operandos sea real, para que el resultado sea real. Así la división 2/3 regresa
0 y 2/3.0 regresa 0.6666.
Java tiene los mismos operadores de asignación que C++. El símbolo = representa la
asignación sencilla:
a = 2;
a = 2;
a++; // a vale ahora 3
También existen los operadores aritméticos con asignación como muestra la siguiente tabla:
19
Expresión Significado
x += y x=x+y
x -= y x=x–y
x *= y x=x*y
x /= y x=x/y
Java maneja los mismos operadores de comparación que C++: menor que (<), menor o
igual que (<=), mayor que (>), mayor o igual que (>=), igual que (==) y distinto que (!=).
Java utiliza 2 símbolos para la operación AND (Y), el & y el &&. La diferencia es que el
operador & evalúa ambos lados de la expresión y el && puede que no evalúe la parte
derecha si la parte izquierda es falsa (y por lo tanto ya sabe que toda la expresión será
falsa). A este comportamiento se le conoce como evaluación en cortocircuito. El uso de
uno u otro operador solo es relevante si la parte derecha de la expresión tiene efectos
laterales como una asignación.
int x = 2, a = 10;
if ((a < 0) & (x++ > 0))
instrucciones
El operador & evalúa la expresión de la izquierda (a < 0) y aunque es falsa evalúa la parte
derecha y por lo tanto incremente el valor de x a 3.
int x = 2, a = 10;
if ((a < 0) && (x++ > 0))
instrucciones
La mayor parte de los autores recomienda usar el operador && y no poner asignaciones en
las condiciones.
Para la operación OR (O) también hay 2 operadores, el | y el ||. Al igual que en el AND, el |
evalúa las dos partes de la expresión y el || no evalúa la parte derecha si la parte izquierda es
verdadera y por lo tanto sabe que toda la expresión es verdadera.
20
Para la operación NOT (no) el operador es el !.
3.5.6 Operador ? :
(z > 0 ? –1 : 1)
int x;
x instanceof int // regresa verdadero
x instanceof double // regresa falso
El operador new crea nuevas instancias de clases. Esto se verá con más detalle en el
capítulo siguiente.
3.6 Instrucciones
Java tiene las mismas instrucciones y sintaxis que C++. Las instrucciones van separadas
por punto y coma. Los bloques de instrucciones de agrupan con corchetes { y }. Vamos a
ver un breve repaso de la sintaxis de cada una de las instrucciones.
21
3.6.1 Instrucción if
Sintaxis:
if (condición)
instrucción;
La palabra reservada else sirve para ejecutar una instrucción alterna si la condición es falsa.
Sintaxis:
if (condición)
instrucción 1;
else
instrucción 2;
if ((n % 2) == 0)
System.out.println (n + " es par");
else
System.out.println (n + " es impar");
Sintaxis:
for (inicio; condición; postcondición)
instrucción;
22
3.6.3 Instrucción while
Sintaxis:
while (condición)
instrucción;
Este segmento de código muestra el uso de un while para escribir el índice del primer
elemento negativo de un arreglo o un mensaje de error si no existe ninguno.
Sintaxis:
do {
instrucción;
} while (condición);
i = 0;
do {
System.out.println ("Hola mundo");
i++;
} while (i < 10);
23
3.6.5 Instrucción switch
Sintaxis
switch (expresión) {
case valor 1 : instrucción 1;
case valor 2 : instrucción 2;
...
[default : instrucción n;] // el corchete cuadrado indica que es opcional
}
La expresión se evalúa y se compara con cada uno de los valores de la parte case. Si
encuentra una coincidencia ejecuta las instrucciones a partir de ese caso. Si no encuentra
ninguna coincidencia ejecuta la instrucción correspondiente a la parte default si es que está
presente o continua con la siguiente instrucción al switch si no hay default.
Se puede indicar que solo ejecute un caso usando la instrucción break (ver sección 3.6.7)
como en el siguiente segmento de código, donde dado un número entero que representa el
mes (1 es enero, 2 es febrero, ..., 12 es diciembre) asigna en la variable día el número de
días del mes o –1 si el número de mes está fuera de rango.
switch (mes) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: dia = 31;
break;
case 4:
case 6:
case 9:
case 11: dia = 30;
break;
case 2: dia = 28;
break;
default: dia = -1;
}
La instrucción return sirve para salir de un método. Si el método regresa un valor el return
va seguido de una expresión que se convertirá en el valor del método. En el capítulo
siguiente se explicarán con más detalle los métodos que regresan valores y se verán
ejemplos del uso del return.
24
3.6.7 Instrucción break
La instrucción break sirve para salir de un switch. El break también se puede utilizar para
terminar un ciclo for, while o do while como en el ejemplo siguiente que escribe 10 veces
el letrero "Hola mundo" en la pantalla:
int i = 0;
while (true) {
System.out.println ("Hola mundo");
i++;
if (i == 10)
break;
}
Si el ciclo está anidado dentro de otro ciclo, la ejecución continúa con el ciclo externo.
Este segmento de código muestra el uso del continue dentro de un ciclo para contar los
elementos positivos de un arreglo.
int cuenta = 0;
for (int i = 0; i < vector.length; i++) {
if (vector[i] < 0)
continue;
cuenta++;
}
System.out.println ("El arreglo tiene " + cuenta + "elementos positivos");
25
26
Capítulo 4 Clases y objetos en Java.
4.1 Introducción
Al programar en Java siempre se tienen que definir por lo menos una clase. El archivo que
contiene esa clase debe llamarse exactamente igual que la clase (con todo y mayúsculas) y
debe tener la extensión .java. Es posible programar varias clases en un archivo, pero solo
una de ellas podrá ser pública (eso por ahora no tiene mayor inconveniente) y el archivo
deberá llamarse igual que la clase pública.
Cada clase tiene variables y métodos definidos. Los métodos se programan de una manera
muy semejante a los procedimientos y funciones de C++.
Las aplicaciones deben tener un método llamado main (excepto en los applets) de tipo
estático (static), público (public) y void y con un argumento de tipo arreglo de strings
(String[]).
En el caso de los applets, como se verá en el capítulo correspondiente, deben definir, ya sea
un método llamado init o bien uno llamado paint.
Listado 4-1
public class Punto {
public int x = 0;
public int y = 0;
}
Este código está creando una clase, y a la vez un nuevo tipo, llamada Punto. La clase Punto
tiene dos variables enteras de instancia x y y. La palabra public significa que cualquier otra
clase puede accesar libremente esas variables.
El listado 4-2 muestra como otra clase, llamada pruebaPunto utiliza la clase Punto que se
acaba de declarar para dos objetos de tipo Punto que representan a los puntos en el plano
(20, 10) y (5, 7).
27
Listado 4-2
public class pruebaPunto {
public static void main (String args[])
{
Punto p1 = new Punto ();
p1.x = 20; p1.y = 10;
Punto p2 = new Punto ();
p2.x = 5; p2.y = 7;
System.out.println ("El punto 1 es x = " + p1.x + " y = " + p1.y);
System.out.println ("El punto 2 es x = " + p2.x + " y = " + p2.y);
}
}
La clase Punto no tiene ningún método main por lo tanto no puede correr por sí sola. La
clase pruebaPunto si lo tiene y por lo tanto es la que puede correr. Para poder correr este
ejemplo hay que copiar el código en 2 archivos llamado Punto.java y pruebaPunto.java
respetando las mayúsculas y minúsculas. Por ahora los 2 archivos deben estar en el mismo
directorio, se compilan por separado, usando el comando javac y se corre la clase
pruebaPunto (es la que tiene el main) invocando al intérprete con el comando java como se
muestra en la figura 4-1.
Las variables de instancia y los métodos se accesan usando lo que se conoce como la
notación punto. En este ejemplo, si tenemos un objeto asignado a la variable p1 y ese
objeto tiene una variable llamada x, entonces el valor de esa variable se accesa mediante
p1.x.
28
4.4 Constructores.
Los constructores son métodos que se utilizan para inicializar objetos cuando son creados.
Los constructores siempre tienen el mismo nombre que la clase y se invocan de manera
automática al usar el operador new. Puede haber varios constructores con el mismo nombre
pero con distintos argumentos (sobrecarga del constructor). Al momento de crear un objeto
nuevo Java sabe que constructor invocar, si hay más de uno, por el número y el tipo de
argumentos que se pasen en el new.
El listado 4-3 muestra la clase Punto con un constructor. El listado 4-4 muestra como la
clase pruebaPunto invoca al constructor de Punto cuando crea los objetos.
Listado 4-3
public class Punto {
public int x;
public int y;
Listado 4-4
public class pruebaPunto {
public static void main (String args[])
{
Punto p1 = new Punto (20, 10);
Punto p2 = new Punto (5, 7);
System.out.println ("El punto 1 es x = " + p1.x + " y = " + p1.y);
System.out.println ("El punto 2 es x = " + p2.x + " y = " + p2.y);
}
}
Listado 4-5
public class asigna {
29
public static void main (String args[])
{
Punto p1 = new Punto (20, 10);
Punto p2 = p1;
p1.x = 2; p1.y = 8;
System.out.println ("El punto 1 es x = " + p1.x + " y = " + p1.y);
System.out.println ("El punto 2 es x = " + p2.x + " y = " + p2.y);
}
}
El punto 1 es x = 2 y = 8
El punto 2 es x = 2 y = 8
Como vemos el valor de las variables de instancia de p2 cambiaron sin haberlo indicado en
forma explícita. Al momento de asignar p1 a p2 las dos variables se convirtieron en el
mismo objeto. La solución a este problema es crear un nuevo objeto para p2 (hay que
recordar que al crear un nuevo objeto se le asigna memoria) y luego copiar las variables de
instancia de p1. El listado 4-6 muestra una forma de hacerlo.
Listado 4-6
public class asigna {
public static void main (String args[])
{
Punto p1 = new Punto (20, 10);
Punto p2 = new Punto (p1.x, p1.y);
p1.x = 2; p1.y = 8;
System.out.println ("El punto 1 es x = " + p1.x + " y = " + p1.y);
System.out.println ("El punto 2 es x = " + p2.x + " y = " + p2.y);
}
}
El punto 1 es x = 2 y = 8
El punto 2 es x = 20 y = 10
Listado 4-7
public class compara {
30
public static void main (String args[])
{
Punto p1 = new Punto (20, 10);
Punto p2 = new Punto (20, 10);
if (p1 == p2)
System.out.println ("Son iguales");
else
System.out.println ("Son diferentes");
}
}
Son diferentes
Listado 4-8
public class compara {
public static void main (String args[])
{
Punto p1 = new Punto (20, 10);
Punto p2 = new Punto (20, 10);
if ((p1.x == p2.x) && (p1.y == p2.y))
System.out.println ("Son iguales");
else
System.out.println ("Son diferentes");
}
}
Son iguales
4.7 Métodos
Los métodos tienen 5 partes básicas: un modificador public o private para indicar si el
método es visible o no fuera de la clase, el tipo que regresa, el nombre del método, una lista
de parámetros y el cuerpo del método. La forma de invocar un método es con la notación
punto.
31
Veamos ahora la declaración de una clase llamada Rectángulo que representa un rectángulo
en el plano. La clase tiene el constructor sobrecargado y se ha programado un método que
calcula el área del rectángulo.
Listado 4-9
public class Rectangulo {
public int ancho;
public int alto;
public Punto origen;
Este código declara otra clase, y por lo tanto otro tipo, llamada Rectángulo que contiene
dos variables de instancia de tipo entero ancho y alto y una tercera variable origen de tipo
Punto. Hay que notar como el nombre de la clase Punto se utiliza en la declaración de una
variable como el tipo de la variable. Se puede usar el nombre de una clase donde sea que se
pueda usar un tipo primitivo.
Así como ancho es un entero y alto también es un entero, origen es un Punto. Por otro
lado, Rectángulo tiene un Punto. Esta distinción entre es un y tiene un es importante
porque solo un objeto que es un punto puede ser usado cuando se necesita un Punto.
La clase Rectángulo tiene dos constructores. Tienen el mismo nombre pero distinta firma.
La firma de un método es el nombre del método y la lista de los tipos de los argumentos
que recibe.
La clase define también un método llamado área. Este método tiene un modificador public
para indicar que puede ser llamado desde otra clase, tiene un tipo de regreso int para indicar
que regresa un valor entero, luego viene el nombre y entre paréntesis la lista de argumentos
que en este caso está vacía. El cuerpo del método se encierra entre corchetes { y }. Como el
32
método regresa un valor entero debe tener una instrucción return seguida de una expresión
entera.
El listado 4-10 muestra la forma de utilizar la clase Rectángulo. El programa crea dos
instancias de la clase Rectángulo y cada objeto tiene su propia copia de las variables de
instancia y acceso al método área. Hay que notar como el método área se invoca usando la
notación punto y que es necesario crear un objeto para poder llamar a un método de
instancia.
Listado 4-10
public class pruebaRectangulo {
public static void main (String args[])
{
Rectangulo r1 = new Rectangulo (10, 5);
Rectangulo r2 = new Rectangulo (7, 9);
System.out.println ("El área de r1 es: " + r1.area ());
System.out.println ("El área de r2 es: " + r2.area ());
}
}
El área de r1 es: 50
El área de r2 es: 63
Listado 4-11
public class Foo {
public void cambia (int x)
{
x = 4;
System.out.println ("En cambia x es: " + x);
}
public static void main (String args[])
{
int x = 2;
Foo f = new Foo ();
System.out.println ("Antes x es: " + x);
f.cambia (x);
System.out.println ("Despues x es: " + x);
}
}
33
La salida del programa es:
Antes x es: 2
En cambia x es: 4
Despues x es: 2
El método cambia hizo una copia de x. Cuando le asignó el valor 4 lo hizo a la copia y no al
original, al momento de terminar el método la copia de x desaparece y solo queda el
original. Esto quedará más claro en la sección denominada alcance de variables.
Los parámetros de tipo no primitivos (arreglos y clases), se pasan por dirección. El método
tiene la dirección del parámetro y cualquier cambio de valor se hace sobre el original. En el
ejemplo del listado 4-12 se muestra como el método cambia tiene acceso al argumento
original sin importar si tiene o no el mismo nombre que dentro del método.
Listado 4-12
public class Foo2 {
Antes z es: 1 2 3 4 5
Despues z es: 10 5 3 4 5
34
Listado 4-13
public class Foo3 {
Antes x es: 2
Despues x es: 4
Listado 4-14
public class Foo4 {
public void cambia2 (FooAux x)
{
x.a = 4;
x.b = 10;
}
35
Listado 4-15
public class FooAux {
int a;
int b;
• globales a la clase.
• locales a un método.
• locales a un bloque.
Puede haber variables con el mismo nombre, siempre y cuando tengan distintos alcances.
Las variables con alcances más locales inhiben el acceso a las variables más globales.
Cuando se hace referencia a una variable, se busca primero entre las locales al bloque,
luego entre las locales al método y al final entre las globales a la clase. El listado 4-16
muestra un ejemplo de un programa con variables de los 3 tipos.
antes: a es 1, b es 2, c es 3
en el for, b es 0
en el for, b es 1
en el for, b es 2
despues: a es 1, b es 2, c es 10
El objetivo del ejercicio es mostrar como la variable global b no cambió su valor a pesar de
haber sido usada en el ciclo for y como el valor de c si se alteró.
36
Listado 4-16
public class Scope {
int a, b, c; // a, b y c son globales a la clase y accesibles en todos los metodos
37
Listado 4-17
public class Fecha {
int dia;
int mes;
int year;
Fecha (int d)
{
this (d, 10, 2002);
}
void cambiaYear ()
{
year = 2002;
}
38
Listado 4-17 Continuación
void pintaCorto ()
{
System.out.println (dia + "/" + mes + "/" + year);
}
Fecha: 20/2/2005
Fecha: 20/2/2100
Fecha: 20/2/2002
El listado 4.18 muestra un ejemplo del uso de una variable de clase. El objetivo es mostrar
como si un objeto cambia el valor de la variable de clase, esta cambia para todos los demás
objetos.
39
Listado 4-18
public class FamPerez {
String nombre;
static String apellido = "Perez";
int edad;
Los métodos de clase están disponibles sin necesidad de crear una instancia de la clase.
Para invocarlos se usa la notación punto, pero en lugar del objeto se pone la clase. Por
ejemplo, la librería de Java tiene una clase Math que define un conjunto de operaciones
matemáticas que se pueden utilizar desde cualquier programa. Los métodos de la clase
Math son métodos de clase, están declarados con la palabra reservada static. Por esa razón,
si se desea calcular el coseno de un número basta con invocar así el método.
Los métodos de clase no pueden accesar variables de instancia, por lo tanto, una regla para
decidir si un método debe ser de instancia o de clase es analizar si queremos que el método
tenga acceso o no a las variables de instancia. Por lo general los métodos de utilería (como
el que se presenta en el listado 4-19) que no modifican el estado del objeto son los que se
programan como métodos de clase.
40
Listado 4-19
public class Conversion {
Como regla general, es conveniente ocultar las variables de instancia crear métodos
especiales para accesar o modificar esas variables. Los métodos que dependan de la forma
en que está implementada una clase también deberán estar ocultos. Es cuestión de diseño el
decidir que métodos son parte de la interface que la clase presenta al mundo externo y
cuales no.
En Java es muy sencillo proteger variables y métodos. Lo único que hay que hacer es poner
en la declaración la palabra reservada private. Por ejemplo:
4.13 Herencia
En Java todas las clases están organizadas en una jerarquía. Cada clase en la jerarquía
(excepto la clase Object) tiene superclases (las clases que están arriba en la jerarquía) y
subclases (las clases que están abajo en la jerarquía). Las subclases heredan los atributos y
métodos de sus superclases.
41
Por ejemplo, un applet es una subclase de la clase java.applet.Applet. Por eso, al programar
un applet ponemos la línea:
en la definición de la clase.
Listado 4-20
public class Cuadrado extends Rectangulo {
private int lado;
Area: 4
Diagonal: 2.828427
42
Como ejemplo supongamos que estamos programando una nómina para una empresa donde
los empleados tienen un sueldo base y aquellos empleados que tienen personas a su cargo
se les da una prima en el salario. En el programa que se presenta en el listado 4-21 la clase
Empleado tiene un método getSueldo para calcular el salario del empleado. La clase Jefe
extiende a la clase Empleado porque un jefe es un caso especial de empleado y define
(sobrepone) su propio método getSueldo. Cuando creamos una instancia de la clase Jefe e
invocamos el método getSueldo, en realidad estamos invocando el método de la subclase
(en este caso Jefe). Si se necesita invocar el método de la superclase se puede hacer
poniéndole la palabra super.
Listado 4-21
public class Empleado {
private String nombre;
private int sueldo;
43
Listado 4-21 Continuación
44
Capítulo 5 Applets
5.1 Introducción
Como vimos en la sección 1.4.1 un applet es un programa en Java que se incrusta en una
página HTML para agregarle funcionalidad.
Como por seguridad los applets están limitados a no poder accesar el medio ambiente de la
computadora donde corren su principal utilidad es para hacer interfaces gráficas de
aplicaciones de bases de datos. Por supuesto la base de datos debe residir en la
computadora de donde vino el applet. También se pueden programar juegos, programas
interactivos que complementen un texto en línea o que ilustren un concepto en particular,
simulaciones, etc.
• Inicio. Se hace cuando se carga el applet por primera vez y corresponde al método
init().
• Comienzo. Se hace cuando el applet comienza a correr, ya sea después del inicio o si
fué detenido. Corresponde al método start().
• Detención. Un applet se detiene cuando el usuario accesa otra página en su navegador.
Corresponde al método stop().
• Destrucción. Permite liberar recursos al finalizar el applet. Corresponde al método
destroy().
• Dibujo. Actualiza la salida del applet en la pantalla. Corresponde al método
paint(Graphics g). Se invoca cada vez que se necesita que el applet sea redibujado, ya
sea al saltar al primer plano, al moverse la pantalla o cuando vuelve a correr después de
estar detenido.
Un applet debe extender a la clase Applet. Esta clase proporciona implementaciones vacías
de los 5 métodos. Es responsabilidad del programador de applets sobreponer los métodos
que vaya a utilizar. No es necesario sobreponer todos, en la práctica casi siempre solo se
sobreponen o el método init() o el paint(), rara vez los dos a la vez.
45
El listado 5-1 muestra el código de un applet sencillo que solo sobrepone el método paint().
El listado 5-2 tiene el código de la página HTML que invoca al applet y la figura 5-1
muestra la salida que se genera al cargar la página HTML en un navegador.
Listado 5-1
import java.awt.Graphics;
import java.awt.Font;
import java.awt.Color;
import java.applet.*;
Listado 5-2
<HTML>
<HEAD>
<TITLE>Hola Mundo !!!</TITLE>
</HEAD>
<BODY>
<P><H2>Saludos desde Sonora:</H2><P>
<APPLET CODE="HolaAgain.class" WIDTH=350 HEIGHT=325 ALIGN="Left">
</APPLET>
</BODY>
</HTML>
Como se puede ver en el listado 5-2 la etiqueta <APPLET> es la que incrusta el applet en la
página HTML. Esta etiqueta puede tener varios argumentos, los principales son:
46
Figura 5-1
5.3 Argumentos
Los applets pueden recibir argumentos desde el archivo HTML con la etiqueta <PARAM>,
la cual tiene un atributo para el nombre del argumento y otro para el valor. La etiqueta
<PARAM> va dentro de la etiqueta <APPLET>.
Los argumentos se pasan cuando el applet se inicializa. Dentro del método init() se puede
recuperar los valores de los argumentos usando el método getParameter(). Este método
recibe como argumento un string con el nombre del argumento y devuelve un string con el
valor correspondiente a ese argumento o el valor null si el argumento no existe.
El listado 5-3 muestra el código de un applet que lee tres argumentos y escribe un mensaje
en la pantalla. El listado 5-4 presenta la página HTML que carga al applet y le pasa los
valores de los tres argumentos y la figura 5-2 la salida cuando se carga la página HTML.
Listado 5-3
import java.awt.Graphics;
import java.awt.Font;
import java.awt.Color;
import java.applet.*;
47
Listado 5-3 Continuación
public void init ()
{
desde = getParameter ("desde");
if (desde == null)
desde = "aqui";
para = getParameter ("para");
if (para == null)
para = "alla";
mssg = getParameter ("mensaje");
if (mssg == null)
mssg = "no hay mensaje";
}
Listado 5-4
<HTML>
<HEAD>
<TITLE>Hola Mundo !!!</TITLE>
</HEAD>
<BODY>
<P><H2>Saludos desde Sonora:</H2><P>
<APPLET CODE="HolaAgainP.class" WIDTH=600 HEIGHT=400>
<PARAM NAME=desde VALUE="Hermosillo">
<PARAM NAME=para VALUE="el mundo">
<PARAM NAME=mensaje VALUE="Java Rules !!!">
</APPLET>
</BODY>
</HTML>
48
Figura 5-2
5.4 Gráficas
La librería de Java incluye la clase Graphics para hacer dibujos sencillos. Esta clase tiene
métodos para dibujar líneas, rectángulos, círculos, polígonos y arcos.
En los applets el método paint recibe un objeto de tipo Graphics. Al dibujar sobre este
objeto se dibuja dentro del applet y los resultados se desplegarán en la pantalla.
La clase Graphics tiene los siguientes métodos. Hay que aclarar que todos los argumentos
son de tipo int.
49
• drawRoundRect (x, y, ancho, alto, r_hor, r_ver) – Dibuja un rectángulo hueco con las
esquinas redondeadas. Los primeros 4 argumentos tienen el mismo sentido que en los
dos métodos anteriores. Los argumentos r_hor y r_ver determinan que tan lejos de los
limites del rectángulo debe comenzar el redondeo en las esquinas.
• fillRoundRect (x, y, ancho, alto, r_hor, r_ver) – Dibuja un rectángulo lleno con el color
actual y redondeado en las esquinas. Los argumentos son los mismos que en el método
anterior.
• drawPolygon (x[], y[], n) – Dibuja un polígono hueco. Los arreglos x y y guardan
respectivamente las coordenadas x y y de cada una de las esquinas del polígono. El
argumento n es el número de puntos (el tamaño de los arreglos x y y). El polígono se
cierra en forma automática porque siempre se dibuja una línea entre el último punto y el
primero.
• fillPolygon (x[], y[], n) – Dibuja un polígono lleno con el color actual. Los argumentos
son los mismos que en el método anterior.
• drawPolyline (x[], y[], n) – Dibuja una línea quebrada. El resultado se puede pensar que
es un polígono sin cerrar.
• drawOval (x, y, ancho, alto) – Dibuja un óvalo hueco. La forma más fácil de entender el
resultado de este método es imaginar que se dibuja un rectángulo imaginario con una
anchura de ancho pixeles y una altura de alto pixeles, con la esquina superior izquierda
en el punto (x, y) y que el óvalo se dibuja inscrito en el rectángulo. Por lo tanto, el
punto (x, y) está fuera del óvalo. Si ancho es igual que alto, el rectángulo se convierte
en cuadrado y el óvalo se convierte en círculo.
• fillOval (x, y, ancho, alto) Dibuja un óvalo lleno con el color actual. Los argumentos
son los mismos que en el método anterior.
• drawArc (x, y, ancho, alto, grados_ini, largo_grados) – Dibuja un arco hueco. Los
primeros 4 argumentos tienen el mismo sentido que en los dos métodos anteriores. El
argumento grados_ini indica desde que grado se comienza a dibujar el arco. Si
pensamos en los puntos cardinales el grado 0 está al este, el 90 al norte, el 180 al oeste
y el 270 al sur. Por último largo_grados indica la longitud del arco y la dirección de
dibujo. Un valor de 90 significa que se dibujará un cuarto de arco en contra de las
manecillas del reloj, en cambio un valor de –90 también indica un cuarto de arco pero
en el sentido de las manecillas del reloj. Igualmente un valor de 180 significa medio
arco y dependiendo del signo es la dirección.
• fillArc (x, y, base, altura, grados_ini, largo_grados) – Dibuja un arco lleno con el color
actual. Los argumentos son los mismos que en el método anterior.
El listado 5-5 muestra un applet que realiza un dibujo utilizando los métodos de la clase
Graphics. La figura 5-3 presenta la salida del applet.
Listado 5-5
import java.awt.Graphics;
import java.applet.*;
50
Listado 5-5 Continuación
// la plataforma
g.fillRect (0, 250, 290, 290);
// La base
g.drawLine (125, 250, 125, 160);
g.drawLine (175, 250, 175, 160);
// La cubierta
g.drawArc (85, 157, 130, 50, -65, 312);
g.drawArc (85, 87, 130, 50, 62, 58);
g.drawLine (85, 177, 119, 89);
g.drawLine (215, 177, 181, 89);
// Las motas
g.fillArc (78, 120, 40, 40, 63, -174);
g.fillOval (120, 96, 40, 40);
g.fillArc (173, 100, 40, 40, 110, 180);
}
}
Figura 5-3
51
5.5 Tipo de letra
Para cambiar el tipo de letra hay que crear una instancia de la clase Font.
El primer argumento es el nombre del tipo de letra. Los tipos de letra disponibles se pueden
saber usando esta instrucción:
String fontlist[] =
GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames ();
o esta para versiones atrasadas de Netscape y Explorer que usan el JDK 1.1
El tercer argumento es el tamaño en puntos del tipo de letra y depende de cada tipo de letra.
setFont (f)
El listado 5-6 muestra un ejemplo del uso de los tipos de letras y la figura 5-4 la salida del
applet.
Listado 5-6
import java.awt.Font;
import java.awt.Graphics;
import java.applet.*;
52
Listado 5-6 Continuación
g.setFont (f2);
g.drawString ("Este es texto en negrita", 10, 50);
g.setFont (f3);
g.drawString ("Este es texto en cursiva", 10, 75);
g.setFont (f4);
g.drawString ("Este es texto en negrita y cursiva", 10, 100);
}
}
Figura 5-4
5.6 Color
Para cambiar el color hay que crear una instancia de la clase Color:
Se puede usar alguno de los colores ya definidos en la clase Color como Color.white,
Color.red, Color.black, Color.orange, Color.blue, Color.gray, Color.yellow, etc.
53
Hay 3 funciones para cambio de color:
• setColor (c). Cambia el color actual para las operaciones de dibujo a partir de este
momento. El argumento c es un objeto de tipo Color.
• setBackground (c). Cambia el color del fondo al color c.
• setForeground (c). Cambia el color de lo que se haya dibujado sin importar el color en
el que se dibujó.
El listado 5-3 muestra la forma de cambiar el color al texto usando el método setColor. El
listado 5-7 presenta un ejemplo donde se usa el método setBackground para cambiar el
color del fondo y setColor para dibujar figuras de distinto color. La figura 5-5 muestra la
salida del applet.
Listado 5-7
import java.awt.Graphics;
import java.applet.*;
import java.awt.Color;
54
Figura 5-5
5.7 Imágenes
Un applet pueden desplegar imágenes en formato GIF y JPEG.
donde URL es la dirección donde está la imagen y nombre es el nombre del archivo que
contiene la imagen. Para la variable URL hay 3 opciones:
b) Usar la dirección relativa con respecto a donde está la página HTML. Si el directorio
images está abajo de donde está la página, entonces poner:
55
c) Usar la dirección relativa a donde está el applet compilado (archivo .class). Si el
directorio images está abajo de donde está el código objeto, entonces poner:
donde imagen es un objeto de tipo Image, x y y son las coordenadas de la esquina superior
izquierda de la imagen. Las variables ancho y alto indica el ancho y el alto en pixeles con
que se va a desplegar la imagen. Por último, la variable donde es el nombre del objeto que
va a actuar como observador de la imagen que en el caso de los applets es el mismo applet.
El listado 5-8 presenta un applet que despliega una imagen en la pantalla, los métodos
getWidth y getHeight regresan el ancho y el alto con los que se generó la imagen
originalmente. Luego dibuja la imagen con un tamaño de 25%, 50%, 100% y 150% con
respecto al tamaño original. Por último, distorsiona la imagen haciendo que tenga la mitad
del ancho original y una vez y media la altura original. La figura 5-6 muestra la salida de
este applet.
Listado 5-8
import java.awt.Graphics;
import java.applet.*;
import java.awt.Image;
56
Listado 5-8 Continuación
// 100 %
xpos += (ancho / 2) + 10;
g.drawImage (bart, xpos, ypos, this);
// 150 %
xpos += ancho + 10;
g.drawImage (bart, xpos, ypos, (int) (ancho * 1.5), (int) (alto * 1.5), this);
// distorsionado
xpos += (int) (ancho * 1.5 + 10);
g.drawImage (bart, xpos, ypos, ancho / 2, (int) (alto * 1.5), this);
}
}
Figura 5-6
57
58
Capítulo 6 AWT
6.1 Introducción
El AWT (Abstract Windowing Toolkit, herramienta abstracta de ventanas), proporciona
componentes para desarrollar interfaces gráficas, incluyendo etiquetas, botones, menús,
checkboxes, campos de texto, choices, etc. Tiene contenedores como ventanas, applets,
paneles, lienzos y diálogos que pueden contener a otros contenedores o a otros
componentes. Puede manejar eventos de ratón y hacer que un componente responda a un
click. La ventaja de AWT es que es independiente del sistema operativo y asegura que la
interface gráfica se verá igual en cualquier computadora que tenga instalado el JDK.
La figura 6-1 muestra un applet que utiliza AWT para programar su interface gráfica. Se
pueden ver botones, áreas de texto y etiquetas.
Figura 6-1
De entrada los applets tienen disponible una ventana, la del navegador, para poder agregar
los componentes que utilicen, en cambio las aplicaciones necesitan crear una ventana base
antes de comenzar a usar los componentes. Fuera de esto, y de las restricciones naturales de
59
los applets, la programación de interfaces gráficas de usuario usando AWT es igual en
applets que en aplicaciones.
Cada componente corresponde a una clase. Para utilizar un componente primero hay que
crear un objeto de ese tipo y luego agregarlo al contenedor usando el método add.
6.2.1 Etiquetas
Una etiqueta es un texto no editable que despliega un letrero en la pantalla. Para definir una
etiqueta hay que crear un objeto de tipo Label indicando el texto de la etiqueta y
opcionalmente una alineación:
Si en algún momento se desea cambiar el texto de la etiqueta se puede hacer con el método
setText.
El listado 6-1 presenta un ejemplo de un applet que despliega 2 etiquetas. La figura 6-2
muestra la salida del programa.
Listado 6-1
import java.awt.*;
import java.applet.*;
60
Figura 6-2
6.2.2 Botones
Un botón es un componente gráfico que activa algún evento cuando se le oprime usando el
ratón. Para definir un botón hay que crear un objeto de tipo Button indicando el texto que
desplegará el botón:
Luego habría que indicarle la acción que realizará al ser oprimido pero eso se verá más
adelante en la sección 6.4.
Si en algún momento se desea cambiar el texto del botón se puede invocar al método
setLabel.
El listado 6-2 presenta un applet que despliega dos botones. La figura 6-3 muestra la salida
de este applet.
61
Listado 6-2
import java.awt.*;
import java.applet.*;
Figura 6-3
6.2.3 Checkboxes
Para definir un checkbox hay que crear un objeto de tipo Checkbox indicando un texto
como etiqueta y opcionalmente un booleano para indicar si de entrada está marcada o no:
62
Si se desea agrupar varios checkboxes, primero hay que crear un objeto de tipo
CheckboxGroup y luego al momento de crear los checkboxes se indica que pertenecen al
mismo grupo.
if (cb2.getState ())
...
El listado 6-3 presenta un applet que despliega 5 checkboxes no agrupados y por lo tanto
más de uno puede estar activado. La figura 6-4 muestra la salida. En cambio el applet del
listado 6-4 declara 2 grupos de checkboxes. En cada grupo solo uno de ellos puede estar
activado. La figura 6-5 muestra la salida de este último applet.
Listado 6-3
import java.awt.*;
import java.applet.*;
63
Figura 6-4
Listado 6-4
import java.awt.*;
import java.applet.*;
64
Figura 6-5
6.2.4 Choices
Un choice es un menú del cual se puede escoger solo una opción. Las listas (que se verán
sección 6.5.4 permiten seleccionar más de una opción). Para usar un choice hay que
declarar un objeto de tipo Choice y luego usar el método add para agregar la lista de
opciones.
Para saber que opción fue seleccionada se usa el método getSelectedIndex que regresa un
número entre 0 y n – 1, donde n es el número de elementos del choice, indicando el índice
del elemento seleccionado.
if (ch_deportes.getSelectedIndex () == 0)
...
Si se desea seleccionar una opción desde un programa se utiliza el método select pasando
como argumento el índice de la opción que se desea quede seleccionada.
ch_deportes.select (2);
65
El listado 6-5 presenta un applet que despliega un choice de 5 opciones. La figura 6-6
muestra la salida.
Listado 6-5
import java.awt.*;
import java.applet.*;
Figura 6-6
66
6.2.5 Campos de texto
Un campo de texto es un componente que permite capturar y editar una línea de texto. Para
usar un campo de texto hay que crear un objeto de tipo TextField indicando el número de
caracteres de ancho y opcionalmente un texto inicial.
Se puede hacer que un campo de texto oculte el texto mientras se escribe en él usando el
método setEchoChar, pasando como argumento el carácter que se desea desplegar en lugar
del texto que se escribe.
Para obtener el texto que se escribió en un campo de texto se usa el método getText.
El listado 6-6 presenta un applet con 3 campos de texto. El tercero oculta con asteriscos los
caracteres que se le escriban. La figura 6-7 muestra la salida del programa.
Listado 6-6
import java.awt.*;
import java.applet.*;
67
Figura 6-7
6.3 Diseños
6.3.1 Definición
AWT tiene cuatro diseños básicos. Cada diseño corresponde a una clase. Para usar un
diseño primero hay que instanciar una de las clases y luego invocar el método setLayout
con pasando como argumento el objeto del tipo de diseño.
El diseño de flujo distribuye los componentes de izquierda a derecha por renglones. Los
renglones se pueden alinear a la izquierda, al centro o a la derecha.
68
El listado 6-7 se presenta un applet que agrega 6 botones de acuerdo a un diseño de flujo
centrado y con un espacio entre componentes de 30 pixeles en forma horizontal y de 10
verticales. La figura 6-8 muestra la salida del applet, es importante notar como los botones
se colocan por líneas en el área reservada para el applet mientras quepan. Si el tamaño de la
ventana cambia, los botones se acomodan al nuevo tamaño y puede que ocupen más o
menos renglones.
Listado 6-7
import java.awt.*;
import java.applet.*;
69
Figura 6-8
El listado 6-8 presenta un applet que especifica una parrilla de 4 columnas y 2 renglones,
con un espacio entre componentes de 40 pixeles en forma horizontal y 30 en forma vertical.
La figura 6-9 muestra la salida del programa.
Listado 6-8
import java.awt.*;
import java.applet.*;
70
Figura 6-8 Continuación
Label lbl_telefono = new Label ("Introduzca su telefono:");
Label lbl_passwd = new Label ("Introduzca su password:");
TextField tf_nombre = new TextField (20);
TextField tf_telefono = new TextField (10);
TextField tf_passwd = new TextField (20);
Button btn_continuar = new Button ("Continuar");
Button btn_cancelar = new Button ("Cancelar");
Figura 6-9
71
6.3.4 Diseño de borde
El diseño de borde divide el contenedor en 5 zonas, norte, sur, centro, oeste y este (ver
figura 6-10). En cada zona cabe un componente.
Figura 6-10
Para usar un diseño de borde hay que crear un objeto de tipo BorderLayout especificando
opcionalmente el espacio horizontal y vertical entre pixeles
El listado 6-9 presenta el applet que generó la pantalla que se ilustra en la figura 6-10.
72
Listado 6-9
import java.awt.*;
import java.applet.*;
Al igual que el diseño de parrilla normal, el diseño de parrilla global divide el contenedor
en una cuadrícula de m renglones y n columnas, y en cada celda cabe un componente. Las
diferencias son que una celda puede ocupar más de un renglón o más de una columna y que
los componentes no se agregan por renglones sino que hay que indicar la columna y el
renglón de la celda donde va a colocarse el componente.
Para usar un diseño de parrilla global se usan dos clases: la clase GridBagLayout para el
diseño en general y la clase GridBagConstraints para definir las restricciones de cada
componente.
Para cada componente que se vaya a agregar primero se definen sus restricciones, luego se
le avisa al diseño cuáles son esas restricciones y por último se agrega el componente.
73
• gridheight – Indica el número de renglones que ocupa la celda.
• weightx – Indica el tamaño horizontal relativo de la celda con respecto a la suma de
todos los tamaños horizontales de las celdas en el renglón. Esta restricción sólo tiene
sentido para las celdas en el primer renglón.
• weighty – Indica el tamaño vertical relativo de la celda con respecto a la suma de todos
los tamaños verticales de las celdas en el renglón. Esta restricción sólo tiene sentido
para las celdas en la primera columna.
• fill – Indica hacia donde va a extenderse el componente si el componente se hace más
grande. Puede valer NONE (no se extiende), VERTICAL, HORIZONTAL o BOTH
(vertical y horizontal).
• anchor – Indica hacia donde, dentro de la celda, se coloca el componente. Puede valer
NORTH (se pega hacia arriba, pero dentro de la celda), SOUTH (abajo), WEST
(izquierda), EAST (derecha), NORTHWEST (esquina superior izquierda),
NORTHEAST (esquina superior derecha), SOUTHWEST (esquina inferior izquierda) o
SOUTHEAST (esquina inferior derecha).
• ipadx – Indica el espacio extra horizontal dentro de la celda.
• ipady – Indica el espacio extra vertical dentro de la celda.
Una vez que se especifica cada restricción se le avisa al diseño con el método
setConstraints pasando como parámetro el componente y el objeto de tipo
GridBagConstraints.
add (componente);
El listado 6-10 presenta un applet que utiliza el diseño de parrilla global para colocar los
componentes en 3 renglones y 2 columnas. El componente del tercer renglón ocupa las dos
columnas porque su restricción gridwidth vale 2. La figura 6-11 muestra la salida.
Listado 6-10
import java.awt.*;
import java.applet.*;
74
Listado 6-10 Continuación
Button btn_continuar = new Button ("Continuar");
// Etiqueta de nombre
gbc.gridx = 0; gbc.gridy = 0;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 50; gbc.weighty = 30;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.EAST;
gbl.setConstraints (lbl_nombre, gbc);
add (lbl_nombre);
// Textfield de nombre
gbc.gridx = 1; gbc.gridy = 0;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 50; gbc.weighty = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.WEST;
gbl.setConstraints (tf_nombre, gbc);
add (tf_nombre);
// Etiqueta de telefono
gbc.gridx = 0; gbc.gridy = 1;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 30;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.EAST;
gbl.setConstraints (lbl_telefono, gbc);
add (lbl_telefono);
// Textfield de telefono
gbc.gridx = 1; gbc.gridy = 1;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.WEST;
gbl.setConstraints (tf_telefono, gbc);
add (tf_telefono);
// Etiqueta de password
gbc.gridx = 0; gbc.gridy = 2;
gbc.gridwidth = 1; gbc.gridheight = 1;
75
Listado 6-10 Continuación
gbc.weightx = 0; gbc.weighty = 30;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.EAST;
gbl.setConstraints (lbl_passwd, gbc);
add (lbl_passwd);
// Textfield de password
gbc.gridx = 1; gbc.gridy = 2;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.WEST;
gbl.setConstraints (tf_passwd, gbc);
tf_passwd.setEchoChar ('*');
add (tf_passwd);
// Boton de continuar
gbc.gridx = 0; gbc.gridy = 3;
gbc.gridwidth = 2; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 10;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (btn_continuar, gbc);
add (btn_continuar);
}
}
76
Figura 6-11
6.4 Eventos
6.4.1 Introducción
Java soporta varios tipos de eventos. Cada vez que ocurre alguna acción de las que se listan
a continuación se genera un evento que puede ser atrapado por un programa:
77
• Eventos de campo de texto. Se está escribiendo sobre el campo de texto. Se dio un enter
sobre el campo de texto.
• Eventos de foco. El componente obtuvo o perdió el foco. El foco se obtiene cuando se
da un click al ratón sobre un componente.
Hay dos estrategias para definir oidores: la primera es usar una clase que tenga un solo
método por cada tipo de evento que atienda todos los eventos que se generen de ese tipo. La
segunda estrategia consiste en declarar oidores anónimos, uno por cada componente que
pueda generar el evento en particular. La ventaja de la primera estrategia es que el manejo
de eventos se centraliza en un solo método. La desventaja es que ese método debe ser capaz
de distinguir cuál componente fue el que generó el evento. Respecto a la segunda estrategia,
la ventaja es que no es necesario distinguir nada, cada componente tiene su propio oidor y
el código se vuelve más legible y elegante. La desventaja es que la cantidad de código
generado se vuelve mayor. En mi opinión la ventaja de los oidores anónimos sobrepasa la
desventaja y por eso en este curso se definen oidores anónimos para el manejo de eventos.
En las secciones siguientes vamos a revisar los eventos más utilizados que son los de botón,
de choice y de checkbox.
Los botones generan un evento de acción al ser oprimidos con el ratón. El programa debe
registrar un oidor por cada botón en que esté interesado. A esta acción se le conoce como
registrar el oidor y se hace con el método addActionListener.
78
Lo que está haciendo el código anterior es crear una instancia anónima de la clase
ActionListener para cada botón y registrarla como oidor de ese botón usando su método
addActionListener. La instancia anónima está sobreponiendo el método actionPerformed
que por definición es el método que la máquina virtual de Java invoca cuando se genera un
evento de acción que en este caso se genera al oprimir el botón.
El listado 6-11 presenta el código de un applet que tiene dos campos de texto y dos botones,
uno tiene la etiqueta de Continuar y otro de Limpiar. El botón de Continuar copia el texto
que se haya tecleado en el campo de texto superior al inferior. El botón de Limpiar borra el
texto de ambos campos de texto. La figura 6-12 muestra la salida del programa.
Listado 6-11
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
79
Listado 6-11 Continuación
// Boton de continuar
gbc.gridx = 0; gbc.gridy = 1;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 10;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (btn_continuar, gbc);
add (btn_continuar);
// Boton de limpiar
gbc.gridx = 1; gbc.gridy = 1;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (btn_limpiar, gbc);
add (btn_limpiar);
// Etiqueta de esto
gbc.gridx = 0; gbc.gridy = 2;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 50; gbc.weighty = 30;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.EAST;
gbl.setConstraints (lbl_esto, gbc);
add (lbl_esto);
// Textfield de esto
gbc.gridx = 1; gbc.gridy = 2;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 50; gbc.weighty = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.WEST;
gbl.setConstraints (tf_esto, gbc);
add (tf_esto);
// Agrega los oidores
btn_continuar.addActionListener (
new java.awt.event.ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
tf_esto.setText (tf_algo.getText ());
}
});
btn_limpiar.addActionListener (
new java.awt.event.ActionListener ()
{
80
Listado 6-11 Continuación
public void actionPerformed (ActionEvent e)
{
tf_algo.setText ("");
tf_esto.setText ("");
}
});
}
}
Figura 6-12
Un choice genera un evento cuando se selecciona una opción. Al igual que en el caso de los
botones hay que registrar un oidor, solo que en el caso de los choices el registro se hace con
el método addItemListener, el oidor debe ser del tipo ItemListener y el método que se
sobrepone es itemStateChanged.
81
El listado 6-12 presenta un applet que tiene un choice y un campo de texto. Cada vez que se
selecciona una opción del choice el campo de texto despliega el nombre de la opción. La
figura 6-13 muestra la salida del applet una vez que se seleccionó la opción 4.
Listado 6-12
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
82
Listado 6-12 Continuación
gbc.anchor = GridBagConstraints.WEST;
gbl.setConstraints (tf_opcion, gbc);
add (tf_opcion);
// Agrega los oidores
c.addItemListener (
new java.awt.event.ItemListener ()
{
public void itemStateChanged (ItemEvent e)
{
tf_opcion.setText (c.getSelectedItem ());
}
});
}
}
Figura 6-13
Los checkboxes generan un evento al ser marcados o desmarcados. Al igual que en el caso
de los choices hay que registrar un oidor con el método addItemListener, el oidor debe ser
del tipo ItemListener y el método que se sobrepone es itemStateChanged.
83
código que se desea que se ejecute al marcar o desmarcar el checkbox 1
}});
El listado 6-13 presenta un applet que tiene dos checkboxes y un campo de texto. Cada vez
que se marca o se desmarca un checkbox se escribe un mensaje alusivo a la acción en el
campo de texto. La figura 6-14 presenta la salida después de marcar el primer checkbox.
Listado 6-13
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
84
Listado 6-13 Continuación
gbl.setConstraints (lbl_mssg, gbc);
add (lbl_mssg);
// Textfield de mensaje
gbc.gridx = 1; gbc.gridy = 1;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 50; gbc.weighty = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.WEST;
gbl.setConstraints (tf_mssg, gbc);
add (tf_mssg);
// Agrega los oidores
cb1.addItemListener (
new java.awt.event.ItemListener ()
{
public void itemStateChanged (ItemEvent e)
{
if (cb1.getState ())
tf_mssg.setText ("se activo checkbox 1");
else
tf_mssg.setText ("se desactivo checkbox 1");
}
});
cb2.addItemListener (
new java.awt.event.ItemListener ()
{
public void itemStateChanged (ItemEvent e)
{
if (cb2.getState ())
tf_mssg.setText ("se activo checkbox 2");
else
tf_mssg.setText ("se desactivo checkbox 2");
}
});
}
}
85
Figura 6-14
Como se dijo anteriormente los paneles pueden tener su propio diseño especificado con el
método setLayout.
p.setLayout (diseño);
Todo lo que se ha dicho sobre agregar componentes con el método add es válido para los
paneles.
p.add (botón);
p.add (checkbox);
86
El uso de paneles puede mejorar el diseño de una interface gráfica evitando que los
componentes se vean alineados como si estuvieran en una parrilla gigante. Una regla de
diseño especifica que los componentes que están relacionados entre sí se coloquen juntos
en un panel. El listado 6-14 presenta un applet que utiliza 3 paneles en un diseño de parrilla
vertical. El panel de en medio tiene a su vez dos paneles para que sus componentes no se
amontonen en un solo lado. La figura 6-15 muestra la salida del programa.
Listado 6-14
import java.awt.*;
import java.applet.*;
87
Listado 6-14 Continuación
pnl_3.add (cb_c);
pnl_2.add ("West", pnl_3);
// panel 4
pnl_4.setLayout (new GridLayout (1, 3, 30, 10));
pnl_4.add (lbl_1);
ch_1.add ("A"); ch_1.add ("B"); ch_1.add ("C");
ch_2.add ("1"); ch_2.add ("2");
pnl_4.add (ch_1);
pnl_4.add (ch_2);
pnl_2.add ("East", pnl_4);
// panel 5
pnl_5.setLayout (new FlowLayout (FlowLayout.CENTER, 10, 30));
pnl_5.add (btn_1);
pnl_5.add (btn_2);
}
}
Figura 6-15
6.5.2 Lienzos
88
La clase Canvas define un método paint vacío. La clase que extienda a Canvas sobrepone
el método paint para dibujar o desplegar una imagen de la misma forma en que lo hace el
método paint de un applet. Si se revisa el manual de Java encontraremos que tanto la clase
Canvas como la clase Applet son subclases de la clase Component y de ella heredan el
método paint. La clase Component representa objetos que pueden ser desplegados en la
pantalla y pueden interactuar con el usuario. Otras subclases de Component son
precisamente las clases que definen los componentes que ya vimos como Panel, Button,
TextField, etc.
El listado 6-15 presenta un applet que del lado izquierdo coloca un lienzo donde dibuja una
lámpara sobre una mesa y del lado derecho un panel donde hay dos choices que controlan
el color con que se dibujan la mesa y la lámpara. La clase miCanvas es la que realmente
hace el dibujo en su método paint y además tiene que definir dos métodos para que el
applet le avise si cambia el color. La figura 6-16 muestra la salida del applet.
Por otra parte el listado 6-16 presenta un applet que utiliza un lienzo para desplegar una
imagen GIF. El método paint de la clase idCanvas es el que despliega la imagen. La figura
6-17 muestra la salida de este applet.
Listado 6-15
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
89
Listado 6-15 Continuación
color_lampara.add ("Negro"); color_lampara.add ("Rojo");
color_lampara.add ("Azul"); color_lampara.add ("Verde");
pnl_1.add (color_lampara);
// oidores
color_mesa.addItemListener (
new java.awt.event.ItemListener ()
{
public void itemStateChanged (ItemEvent e)
{
mc.cambiaColorMesa (color_mesa.getSelectedIndex ());
}
});
color_lampara.addItemListener (
new java.awt.event.ItemListener ()
{
public void itemStateChanged (ItemEvent e)
{
mc.cambiaColorLampara (color_lampara.getSelectedIndex ());
}
});
}
}
90
Listado 6-15 Continuación
g.drawArc (85, 87, 130, 50, 62, 58);
g.drawLine (85, 177, 119, 89);
g.drawLine (215, 177, 181, 89);
g.fillArc (78, 120, 40, 40, 63, -174); // dibuja las motas
g.fillOval (120, 96, 40, 40);
g.fillArc (173, 100, 40, 40, 110, 180);
}
Figura 6-16
91
Listado 6-16
import java.awt.*;
import java.applet.*;
92
Listado 6-16 Continuación
pnl_3.add (lbl_height1);
pnl_3.add (lbl_eyes1); pnl_3.add (lbl_weight1); pnl_3.add (lbl_sex2);
pnl_3.add (lbl_height2); pnl_3.add (lbl_eyes2); pnl_3.add (lbl_weight2);
pnl_east.add ("South", pnl_3);
add ("East", pnl_east);
}
}
Figura 6-17
93
6.5.3 Áreas de texto
Un área de texto es un componente que se utiliza para leer datos de entrada de manera
semejante al campo de texto. La diferencia es que, mientras el campo de texto puede leer
solo una línea de texto, el área de texto puede leer varias. Si el texto es más grande que el
tamaño con el que se despliega el área de texto automáticamente se colocan barras de scroll
horizontales o verticales según sea el caso.
Para utiliza un área de texto hay que crear un objeto de tipo TextArea pasando como
argumentos al constructor en forma opcional un string inicial, un tamaño preferido de
desplegado en renglones y columnas y un indicador para que despliegue o no barras de
scroll de inicio.
A pesar de que el texto esté en varias líneas, el área de texto lo trata como un string, es
decir, como si fuera una sola cadena de caracteres. Cuando desde un programa se altera el
texto de un área de texto es responsabilidad del programador insertar saltos de línea ('\n')
dentro del string para que el texto se visualice por renglones.
El listado 6-17 presenta un applet con dos áreas de texto. Después de escribir un texto
cualquiera en la primera área de texto, al oprimir el botón de Cuenta, la segunda área de
texto despliega el número de líneas y de caracteres que se escribieron. La figura 6-18
muestra la salida del programa.
Listado 6-17
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
94
Listado 6-17 Continuación
public void init ()
{
setLayout (gbl);
// text area de arriba
gbc.gridx = 0; gbc.gridy = 0;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 100; gbc.weighty = 33;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (ta1, gbc);
add (ta1);
// boton
gbc.gridx = 0; gbc.gridy = 1;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 33;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (btn, gbc);
add (btn);
// text area de abajo
gbc.gridx = 0; gbc.gridy = 2;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 33;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (ta2, gbc);
add (ta2);
btn.addActionListener (
new java.awt.event.ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
String s = ta1.getText ();
int k = 0;
for (int i = 0; i < s.length (); i++)
if (s.charAt (i) == '\n')
k++;
ta2.setText ("Escribiste\n" + k + " renglones\n" + s.length () + " caracteres");
}
});
}
}
95
Figura 6-18
6.5.4 Listas
Una lista es similar al choice que permite seleccionar de entre varias opciones de una lista
con dos diferencias: su presentación es en forma de lista y permite seleccionar más de una
opción.
Para usar una lista hay que crear un objeto de tipo List pasando como argumentos
opcionales el número de opciones que estarán visibles y un indicador si la liste permite o no
opciones múltiples.
96
En las listas que permiten la selección de únicamente un elemento el método
getSelectedIndex devuelve la posición del elemento seleccionado.
El listado 6-18 presenta un applet con un choice, una lista que permite seleccionar un solo
elemento y una lista que permite selección múltiple. Al oprimir el botón, en la parte inferior
se despliegan las opciones que fueron seleccionadas en el choice y en las listas. La figura 6-
19 muestra la salida del programa.
Listado 6-18
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
97
Listado 6-18 Continuación
gbc.gridx = 1; gbc.gridy = 0;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 33; gbc.weighty = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (lst_1, gbc);
add (lst_1);
// lista 2
gbc.gridx = 2; gbc.gridy = 0;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 33; gbc.weighty = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (lst_2, gbc);
lst_2.add ("opcion 1"); lst_2.add ("opcion 2"); lst_2.add ("opcion 3");
lst_2.add ("opcion 4");
add (lst_2);
// boton de revisar
gbc.gridx = 0; gbc.gridy = 1;
gbc.gridwidth = 3; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 20;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (btn_revisar, gbc);
add (btn_revisar);
// etiqueta 1
gbc.gridx = 0; gbc.gridy = 2;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 40;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (lbl_1, gbc);
add (lbl_1);
// etiqueta 2
gbc.gridx = 1; gbc.gridy = 2;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (lbl_2, gbc);
add (lbl_2);
// etiqueta 3
gbc.gridx = 2; gbc.gridy = 2;
gbc.gridwidth = 1; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 0;
98
Listado 6-18 Continuación
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (lbl_3, gbc);
add (lbl_3);
// oidor
btn_revisar.addActionListener (
new java.awt.event.ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
lbl_1.setText ("En el choice la opcion es: " + chs_1.getSelectedIndex ());
lbl_2.setText ("En la lista 1 la opcion es: " + lst_1.getSelectedIndex ());
int idx[] = lst_2.getSelectedIndexes ();
StringBuffer mssg = new StringBuffer ("En la lista 2 las opciones son: ");
for (int i = 0; i < idx.length; i++)
mssg.append (idx[i] + " ");
lbl_3.setText (mssg.toString ());
}
});
}
}
Figura 6-19
99
6.5.5 Frames
Un frame es una ventana que, dependiendo del sistema operativo, cuenta con un título, un
menú de barra, indicadores para minimizar, maximizar o cerrar, y otras características
típicas de las ventanas.
Un frame es un componente contenedor y como tal puede tener su propio diseño y contener
otros componentes de AWT.
Para usar un frame hay que crear un objeto de tipo Frame pasando como parámetro el título
de la ventana.
Cuando se crea un nuevo frame, éste es invisible. El método setVisible hace que el frame
sea visible o de vuelta invisible mediante un argumento booleano que puede valer true (la
ventana se hace visible) o false (el frame se hace invisible).
frm.dispose ();
Por default el indicador de cerrar ventana, que en Windows tiene una marca de cruz y está
en la parte superior derecha del frame, esta inactivo. Es necesario crear un oidor de la clase
WindowAdapter y registrarlo usando el método addWindowListener para indicarle al frame
que se destruya al oprimir ese indicador.
frm.addWindowListener (
new java.awt.event.WindowAdapter ()
{
public void windowClosing (WindowEvent e)
{
100
frm.dispose ();
}
});
El listado 6-19 presenta un applet que crea un frame, le agrega una etiqueta, un campo de
texto y un botón y luego lo hace visible. La figura 6-20 muestra la salida de este programa.
Listado 6-19
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
101
Listado 6-19 Continuación
// boton de ok
gbc.gridx = 0; gbc.gridy = 1;
gbc.gridwidth = 2; gbc.gridheight = 1;
gbc.weightx = 0; gbc.weighty = 20;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
gbl.setConstraints (btn_ok, gbc);
frm_1.add (btn_ok);
frm_1.setLocation (100, 150);
frm_1.setSize (400, 300);
frm_1.setVisible (true);
// oidor
frm_1.addWindowListener (
new java.awt.event.WindowAdapter ()
{
public void windowClosing (WindowEvent e)
{
frm_1.dispose ();
}
});
}
}
Figura 6-20
102
6.5.6 Diálogos
Un diálogo es semejante a un frame en el sentido que es una ventana que puede tener su
propio diseño y contener a otros componentes. Las diferencias son que los diálogos
necesitan tener un frame ligado a ellos, no tienen indicadores de maximizar ni de minimizar
y pueden operar en forma modal. Un diálogo modal impide que sean accesadas otras
ventanas hasta que el diálogo sea cerrado. Por estos motivos y por lo general, los diálogos
se utilizan en forma modal y para avisar de errores en el programa o pedir datos al usuario.
Para usar un diálogo hay que crear un objeto de tipo Dialog pasando como argumento
obligatorio el frame al cual están ligados y opcionalmente un argumento string con el título
del diálogo y una variable booleana para indicar si el diálogo es modal o no modal.
Para que un applet pueda usar un diálogo necesita hacer referencia a la ventana del
navegador que lo contiene. Una forma de conseguirlo es obtener los componentes padres
del applet, usando el método getParent, hasta encontrar un objeto de tipo Frame y pasar
como argumento ese objeto al constructor del diálogo.
El listado 6-20 presenta un applet que abre un diálogo modal y por lo tanto se bloquea. Al
cerrar el diálogo el programa puede continuar y abre un frame. La figura 6-21 muestra la
salida del programa antes de cerrar el diálogo.
Listado 6-20
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
103
Listado 6-20 Continuación
Dialog dlg_1;
104
Listado 6-20 Continuación
frm_1.setSize (400, 300);
frm_1.setVisible (true);
frm_1.addWindowListener (
new java.awt.event.WindowAdapter ()
{
public void windowClosing (WindowEvent e)
{
frm_1.dispose ();
}
});
}
}
Figura 6-21
• Como los applets están corriendo en el navegador ya tienen por default una ventana
contenedora donde pueden agregar componentes.
105
Sin embargo, como ya sabemos que por razones de seguridad, los applets tienen la
restricción de que no pueden accesar los recursos locales de la computadora donde están
corriendo y por eso muchas veces se tienen que programar aplicaciones.
• La aplicación debe crear un frame principal donde pueda colocar sus componentes
AWT. En la práctica lo que se hace es que la clase principal extienda a la clase Frame.
• Las definiciones de los componentes se hacen dentro del constructor de la clase en lugar
de hacerlo en el método init como los applets.
• Deben tener un método main que por lo general su única acción es instanciar la clase
principal (que es de tipo Frame) y hacerla visible.
El listado 6-21 presenta la versión aplicación del applet que se presentó en el listado 6-16 y
que despliega una imagen utilizando un lienzo. Se puede ver que el código es prácticamente
el mismo en las dos versiones. La figura 6-22 muestra la salida del programa.
Listado 6-21
import java.awt.*;
import java.awt.event.*;
DMV ()
{
setBackground (Color.lightGray);
setLayout (new BorderLayout ());
106
Listado 6-21 Continuación
// agrega la foto
Image foto = getToolkit ().getImage ("bart_id.gif");
fotoCanvas cvs_foto = new fotoCanvas (foto, this);
add ("Center", cvs_foto);
// agrega el titulo
pnl_north.setLayout (new BorderLayout ());
lbl_dmv.setFont (new Font ("TimesRoman", Font.BOLD, 18));
pnl_north.add ("Center", lbl_dmv);
add ("North", pnl_north);
// agrega la descripcion
pnl_east.setLayout (new BorderLayout ());
pnl_1.setLayout (new BorderLayout ());
pnl_1.add ("Center", lbl_number);
pnl_east.add ("North", pnl_1);
pnl_2.setLayout (new GridLayout (3, 1));
pnl_2.add (lbl_nombre); pnl_2.add (lbl_calle); pnl_2.add (lbl_ciudad);
pnl_east.add ("Center", pnl_2);
pnl_3.setLayout (new GridLayout (2, 4));
pnl_3.add (lbl_sex1); pnl_3.add (lbl_height1); pnl_3.add (lbl_eyes1);
pnl_3.add (lbl_weight1); pnl_3.add (lbl_sex2); pnl_3.add (lbl_height2);
pnl_3.add (lbl_eyes2); pnl_3.add (lbl_weight2);
pnl_east.add ("South", pnl_3);
add ("East", pnl_east);
setSize (350, 200);
setLocation (200, 100);
addWindowListener (
new java.awt.event.WindowAdapter ()
{
public void windowClosing (WindowEvent e)
{
dispose ();
}
});
}
107
Listado 6-21 Continuación
class fotoCanvas extends Canvas {
Image image;
Figura 6-22
108
Capítulo 7 Archivos
7.1 Definición
En Java un flujo es una secuencia de bytes sin formato. Su origen puede ser un archivo en
disco, un socket de comunicación de entrada, un arreglo, el teclado, etc. Su destino puede
ser otro archivo de disco, un socket de comunicación de salida, otro arreglo, la pantalla, la
impresora, etc. En general los flujos no tienen porque saber cuál es el origen ni el destino
de la información que reciben, son las clases específicas las que determinan el origen y el
destino. La ventaja de hacerlo así es que se pueden agregar orígenes y destinos de
información sin que las clases generales tengan que cambiar.
En este capítulo en particular vamos a estudiar los flujos que tiene que tienen como origen
y como destino un archivo.
Un archivo es una secuencia de bytes que se guarda en disco y que puede actuar como
origen o como destino de un flujo. Los bytes no tienen ningún formato ni tamaño de
registro. El programador es el encargado de ordenar y darle sentido a esa secuencia.
La librería de entrada y salida de Java (java.io) divide las clases que manejan los flujos en
dos grandes categorías: las clases lectoras que se ocupan de los flujos de entrada y las
clases escritoras que se ocupan de los flujos de salida. Un vistazo rápido al manual nos
muestra que la librería define más de 40 clases entre lectoras y escritoras, sin embargo, para
efectos de una introducción al manejo de archivos en Java es suficiente con aprender a usar
cuatro clases especificas de archivos (dos lectoras y dos escritoras) y seis clases generales
de flujos (tres de cada clase). Al final del capítulo presentaremos otra clase general lectora
que funciona para resolver un problema en particular.
El siguiente segmento de código ilustra la forma en que se puede leer un archivo en bloques
de 1000 bytes.
109
La clase InputStreamReader es una clase general que convierte un flujo de bytes en un flujo
de caracteres. Define el método read que puede leer un carácter o un arreglo de caracteres.
Esta clase se utiliza si sabemos que el flujo de entrada es de caracteres de texto. Como la
clase es general y acepta cualquier flujo de bytes de entrada (no solo con origen en un
archivo de disco) hay que pasarle como argumento en el constructor la clase específica
ligada al origen de los datos y que en este caso es FileInputStream.
Para el manejo de archivos hay dos formas para construir un objeto de tipo BufferedReader.
Una es utilizar un objeto InputStreamReader creado sobre un objeto de tipo
FileInputStream:
La ventaja de hacerlo así es que se puede manejar el tamaño del buffer e incluso cambiar la
codificación de los caracteres. La codificación de caracteres es la forma que tiene Java de
convertir bytes de 8 bits en caracteres Unicode de 16 bits. Hay que recordar que en Java el
tipo char ocupa 16 bits y utiliza el código Unicode que a su vez es un superconjunto del
popular código ASCII de 7 bits.
La otra forma es aceptar el tamaño del buffer y la codificación predefinidos, lo cuál muchas
veces es lo más conveniente, y para estos casos se puede usar la clase FileReader que como
argumento en el constructor se le pasa el nombre del archivo.
El listado 7-1 presenta un programa que lee un archivo de texto y lo despliega en la pantalla
línea por línea.
110
Listado 7-1
import java.io.*;
En Java no hay una instrucción directa para leer datos del teclado. El teclado se considera
como origen de un flujo de datos, está asociado con la variable System.in de tipo
InputStreamReader y se trata de la misma manera que cualquier flujo. El listado 7-2
presenta un programa que lee del teclado una línea de texto y un entero.
Listado 7-2
import java.io.*;
111
Listado 7-2 Continuación
linea = kbd.readLine ();
// los numeros hay que convertirlos de string a numero
System.out.print ("escribe un entero: ");
s = kbd.readLine ();
n = new Integer (s).intValue ();
System.out.println ("El string es: " + linea + " y el entero es: " + n);
}
catch (IOException e) {
System.out.println ("Error de I/O");
}
}
}
El siguiente segmento de código muestra la forma en que se lee un archivo de datos que se
sabe trae 1000 enteros.
El listado 7-3 presenta un programa que lee un archivo de datos en el cuál se sabe que
vienen 5 enteros, 3 reales y un booleano en ese orden.
Listado 7-3
import java.io.*;
112
Listado 7-3 Continuación
try {
dis = new DataInputStream (new FileInputStream ("datos.dat"));
}
catch (FileNotFoundException e) {
System.out.println ("No pude abrir el archivo datos.dat");
}
try {
for (int i = 0; i < 5; i++) {
a = dis.readInt ();
System.out.println ("a = " + a);
}
for (int i = 0; i < 3; i++) {
b = dis.readDouble ();
System.out.println ("b = " + b);
}
c = dis.readBoolean ();
System.out.println ("c = " + c);
dis.close ();
}
catch (IOException e) {
System.out.println ("Error al leer");
}
}
}
Para abrir un archivo para escritura hay que crear un objeto de tipo FileOutputStream
pasando como argumento al constructor el nombre del archivo.
El listado 7-4 presenta un programa que recibe el nombre de un archivo, que puede ser de
texto o binario y genera una copia.
113
Listado 7-4
import java.io.*;
114
La clase OutputStreamWriter es una clase general que convierte un flujo de caracteres en
un flujo de bytes. Define el método write para escribir a la salida un carácter o un arreglo
de caracteres. Esta clase se utiliza si sabemos que el flujo de salida es de caracteres de
texto. Como la clase es general y acepta cualquier flujo de bytes de salida (no solo con
destino en un archivo de disco) hay que pasarle como argumento en el constructor la clase
específica ligada al destino de los datos y que en este caso es FileOutputStream. Los
caracteres que recibe la clase se convierten a bytes de acuerdo a una codificación de
caracteres en específico y cada invocación al método write provoca que el convertidor de
codificación sea invocado. Por esta razón el manual de Java recomienda no usar esta clase
por separado, más bien como intermedio de la clase BufferedWriter que veremos a
continuación.
Para el manejo de archivos hay dos formas para construir un objeto de tipo BufferedWriter.
Una es utilizar un objeto OutputStreamReader creado sobre un objeto de tipo
FileOutputStream:
La ventaja de hacerlo así es que se puede manejar el tamaño del buffer e incluso cambiar la
codificación de los caracteres.
La otra forma es aceptar el tamaño del buffer y la codificación predefinidos, lo cuál muchas
veces es lo más conveniente, y para estos casos se puede usar la clase FileWriter que como
argumento en el constructor se le pasa el nombre del archivo.
El listado 7-5 presenta una aplicación que copia un archivo de texto por líneas.
115
Listado 7-5
import java.io.*;
116
ningún destino de datos en particular y por eso, para escribir en un archivo, hay que
mandarle como argumento en su constructor un objeto de tipo FileOutputStream.
El listado 7-6 presenta una aplicación que escribe un archivo de datos con 5 enteros, 3
reales y un booleano en ese orden. Este programa genera el archivo de datos que lee la
aplicación que se presentó en el listado 7-3
Listado 7-6
import java.io.*;
117
7.4 Archivos de datos
En muchas aplicaciones se requiere leer archivos de datos que son generados por otras
aplicaciones y que vienen en formatos especiales. Por ejemplo, un manejador de bases de
datos o una hoja de cálculo permiten exportar datos en formatos de columna fija o
separados por coma.
Los archivos de columna fija son aquellos donde los datos están alineados de tal forma que
cada renglón representa un conjunto de datos afines (lo que se conoce como un registro) y
cada dato representa un valor particular y siempre comienzan en la misma columna. La
figura 7-1 muestra el contenido de un archivo de datos de este tipo. Cada renglón representa
un alumno y las columnas representan su apellido paterno, apellido materno, primer
nombre y carrera respectivamente y están alineados para que siempre comiencen en la
misma columna.
Figura 7-1
Para leer un archivo de columna fija se lee una línea de texto usando el método readLine de
la clase BufferedReader y luego se extraen los valores con el método de la clase String
substring. Opcionalmente al resultado se le puede aplicar el método trim que elimina los
caracteres blancos que haya al principio y al final de un string.
El listado 7-7 presenta una aplicación que lee un archivo con los datos que se muestran en
la figura 7-1 y los escribe en la pantalla.
Listado 7-7
import java.io.*;
118
Listado 7-7 Continuación
try {
String linea;
while ((linea = fd_in.readLine ()) != null) {
String ap_pat = linea.substring (0, 14).trim ();
String ap_mat = linea.substring (14, 24).trim ();
String npila = linea.substring (24, 36).trim ();
String carrera = linea.substring (36, linea.length ()).trim ();
System.out.println (ap_pat + " " + ap_mat + " " + npila + " " + carrera);
}
fd_in.close ();
}
catch (IOException e) {
System.out.println ("Error de I/O " + e);
return;
}
}
}
Los archivos de datos separados por comas son aquellos donde los datos, dentro de los
renglones, vienen separados por comas. La figura 7-2 muestra el contenido de un archivo
de datos separados por coma. Cada renglón representa los extremos de una línea recta. Las
dos primeras columnas son las coordenadas del punto (x1, y1) y las siguientes dos
columnas son las coordenadas del punto (x2, y2).
Figura 7-2
Para leer un archivo de datos separados por comas se podría proceder leyendo una línea del
archivo usando el método readLine y luego buscar las posiciones de las comas y copiar con
el método substring la parte que está entre las comas. Afortunadamente la librería de
entrada y salida de Java tiene una clase llamada StreamTokenizer que toma un flujo de
entrada y lo separa en "tokens" o palabras, permitiendo que los tokens se puedan leer uno a
la vez. La clase reconoce palabras, números, espacios en blanco, strings y comentarios.
119
Una aplicación típicamente crea una instancia de esta clase y luego invoca repetidamente al
método nextToken hasta que regrese el valor TT_EOF indicando que no hay mas tokens
disponibles.
El listado 7-8 presenta una aplicación que lee un archivo con los datos que se muestran en
la figura 7-2 y escribe la suma de las columnas.
Listado 7-8
import java.io.*;
120
La salida de este programa es:
La librería de red de Java (java.net) tiene la clase URL para representar una dirección en
Internet y la clase URLConnection para representar una conexión a una dirección dada.
Para abrir un archivo remoto lo primero es crear un objeto de tipo URL pasando como
argumento al constructor la dirección completa del archivo.
Luego hay que crear un objeto del tipo URLConnection invocando al método
openConnection sobre el objeto de tipo URL y haciendo la conexión mediante el método
connect.
En este momento se puede proceder a leer el archivo por líneas de la misma manera que si
fuera local.
El listado 7-9 presenta un applet que lee un archivo remoto de un servidor de páginas web.
Hay que recordar que los applets tienen la restricción de que no pueden conectarse con
ninguna computadora que no sea donde estaban, en otras palabras el applet y el archivo
deben estar en la misma computadora. Las aplicaciones no tienen esa restricción. La figura
7-3 muestra la salida del applet.
121
Listado7-9
import java.awt.*;
import java.net.*;
import java.io.*;
import java.applet.*;
122
Figura 7-3
123