- -

DESCARGA PARA ESCUCHAR LA RADIO METRO


Listen with Winamp/iTunes



Listen with Windows Media Player

--
-
Radio Metro La Radio Dj.....

- -
-
 

Inicio Java












Simplemente os recomiendo que tengáis cuidado porque en éste caso el bluette es un compilador Java, pero no sé
si es totalmente compatible con el Java de la SDK que estoy tratando yo. En nuestro archivo HolaMundo.java escribiremos:

class HolaMundo
{

public static void main(String[] args)
{

System.out.print ("Hola mundo, soy el primer programa en Java");

System.out.println ("di "+args[0]+" "+args[1]);

}

}

Redactamos el programa escribiendo, como siempre, java HolaMundo.java y ahora podemos ponerlo en marcha. Escribiremos:

java HolaMundo TUNOMBRE TUSAPELLIDOS

y veremos una salida parecida a ésta:

Hola mundo, soy el primer programa en Java de TUNOMBRE TUS APELLIDOS

Si no ponemos el nombre y los apellidos, el programa dará una excepción, que
es parecido a un error a runtime, debido a que en el main se citan arg[0] y arg[1]
que no aparecen. estas excepciones sí son errores a runtime, pero se pueden prever y gestionar
precisamente porque Java es un lenguaje "seguro" y, más que interrumpirse y dar el normal RUNTIME ERROR
que dan los demás lenguajes, da una excepción que, si prevista por el programador, no interrumpe el programa.
En el siguiente capítulo veremos como gestionar posibles excepciones y, también, como utilizarlas para nuestros fines.
Pensemos, por ejemplo, en un programa que lee de los archivos y que no encuentra este archivo: Java dará su excepción, nosotros
la leemos y haremos que lea otro archivo. La versión sin riesgos de excepciones y más espectacular es la siguiente:

class HolaMundo2
{

public static void main(String[] args)

{

System.out.println ("*************************************************");
System.out.println ("** Hola mundo, soy el primer programa en Java **");
System.out.println ("*************************************************");
System.out.println (" |||||");
System.out.println ("0/ x x ");
System.out.println (" | o |");
System.out.println (" |___/|");
System.out.println (" |_____|");

}
}

Llegados a este punto, sólo me queda felicitaros: acabáis de escribir vuestro primer programa en Java.
Si os parece poco, no os procupéis: a partir del captítulo sucesivo veremos las construcciones y entonces nos
desahogaremos escribiendo todos los programas que queramos.

Siguente

Tipos primitivos de Java y valores



Llamamos tipos primitivos de un lenguaje cuando hablamos de tipos de datos ya definidos en el lenguaje y de los que se puede partir para la construcción de expresiones o tipos de compuestos.
Los tipos son muy importantes en todos estos lenguajes de programación y son fundamentales en Java que es un lenguaje que se basa mucho en los tipos. El concepto de tipo es muy natural: si veo un número, por ejemplo, 15.4 puedo decir en seguida el conjunto de números al que pertenece, en este caso al conjunto de los números reales.
Si veo una operación 4 / 5 puedo decir:

4 es de entero entero 5 es de tipo entero y / es una función de dos enteros y que me devuelve un número real. Se escribe así:

/ : ent x ent à float

Entonces, puedo decir que toda la expresión 4/5 es de tipo entero.

Lo que acabamos de hacer es, más o menos, una inferencia de tipos que es una práctica muy utilizada en informática. Para explicarla toda se necesitaría, como con los modelos por objetos, un curso entero.
Los problemas no surgen con estas expresiones, que se llaman cerradas, que no tienen variables, sino con las que tienen variables. Cada lenguaje emplea una técnica suya: algunas usan los tipos para las expresiones, otras establecen el tipo partiendo del contexto de la expresión y da un tipo en secuencia incluso por cada una de las expresiones, y los que, como Java, obligan a declarar todos los tipos de todas las variables desde el principio. Los tipos primitivos de Java son los mismos de los demás lenguajes de programación, sólo que difieren un poco en los valores y son.

boolean
es decir, valores que pueden ser verdaderos o falsos

char los caracteres son de 16 bit y están codificados en Unicode 1.1.5; en los demás lenguajes son ASCII solamente de 8 bit.

byte
enteros de 8 bit con signo, es decir, número entre menos (dos a la séptima) y dos a la octava.

short
enteros de 16 bit con signo.

int
enteros de 32 bit con signo.

long
enteros de 64 bit con signo.

float
reales de 32 bit con coma móvil (IEEE 754-1985).

double
reales de 32 bit con coma móvil (IEEE 754-1985).

Obviamente, a partir de éstos es posible definir nuevos tipos de datos que se llaman compuestos. Por ejemplo, una cadena es un vector de caracteres y es un tipo compuesto.
Como vimos el la lección precedente, en el paquete java.lang están los contenedores para estos tipos de base, es decir, que si escribo ent, me refiero a un número entero, mientras que si escribo Enteger me refiero a las clases enteros.

Si uso las clases, tendré también una serie de atributos y métodos útiles para trabajar con ellos. Por ejemplo, en alguans se definen las constantes MIN_VALUE y MAX_VALUE (Mínimo y máximo valor), en las clases Float y Double encontraremos las constantes NEGATIVE_INFINITY y POSITIVE_INFINITY, NaN para indicar un valor que no es válido y el método isNan() para controlar si un valor es válido. Por ejemplo, se puede utilizar después de una división para controlar que no se haya hecho una división por cero que resultaría catastrófica. Todo esto no existe en los demás lenguajes de programación.
Ahora vamos a ver los literales de cada tipo de Java, es decir los valores constantes que cada tipo puede tener.

El único literal para referirnos a los objetos es null, se puede utilizar cada vez que nos esperamos una referencia a un objeto, null es un objeto que no se ha creado y no es válido: no es de ningún tipo.

Los literales booleani son verdaderos y falsos e indican, respectivamente, el valor cero y el valor falso.

Los literales enteros son cadenas de cifras octales, decimales o exadecimales. El inicio de la constante sirve para escribir la base del número: un cero inicial indica base ocho, 0x o 0X indica base 16 y nada indica los decimales. Por ejemplo, el número 15 en base diez puede representarse como:

15 como decimal
017 como octal
0xf o 0XF como esadecimal.

Las constantes enteras que terminan por l o L se consideran long. Es mejor que terminen por L porque l se confunde fácilmente con la unidad (no se equivoca el compilador, pero sí nosostros que leemos los programas) y si no acaban por una letra se consideran como ent. Si un leteral ent se escribe como un short o como un byte, éste se porta como si lo fuera.

Los literales con coma móvil se escriben como números decimales, con un punto opcional seguido, posiblemente, por un exponente que empieza por e, según la práctica corriente para indicar mantisa-exponente. El número puede llevar detrás una f (F) o una d (D) para indicar que es, con precisión, simple o doble, para default es doble.

35, 35. , 3.5y1, .35y2 representan el mismo número.

El cero puede ser positivo o negativo, si los comparamos obtenemos la equivalencia. Sin embargo, es útil en los cálculos, pensemos en 1d/0d y 1d/-0d.
No es posible conceder una constante doble a una float aunque esté en la serie. Si queremos hacer esta operación, hay que hacer un cambio que se llama casting que analizaremos a continuación.

Los caracteres se ponen entre comilla como, por ejemplo, '2', y los caracteres especiales están representados por unas secuencias, llamadas secuencias de escape. Son:

n newline, a parte

t tab

b backspace, borra a la izquierda

r return, representa el carácter especial ENVIO

f form feed

es el carácter backslash

' comilla

" comillas

ddd es un char que emplea el valor octal (d son cifras octales, por ejemplo 329, tienen que ser de tres o menos cifras y menores de 377), se puede dar también la representación exadecimal, siempre de cuatro cifras. Aquí ponemos en orden los caracteres citados antes con su número exadecimal: u000A, u0009, u0008, u000D, u000C, u005C, u0027 y u0022.

Las cadenas se escriben entre comillas, como por ejemplo "Pietro" y todas las secuencias de escape válidas se pueden introducir en una larga cadena, creando cosas interesantes como, por ejemplo:

System.out.println("tNombre:tPietrontApellido:tCastellucci" );

dará este resultado:

Nombre: Reymon
 Apellido: Huarayo




Variables


 
Las variables son valores modificables, es decir, son nombres que representan un valor de cierto tipo y el valor asociado al nombre se puede variar. Por ejemplo, si digo que X es una variable de tipo entero y después digo que tiene valor 10, escribiendo la expresión 5 + X es como si escribiera la expresión 5 + 10. De todas formas creo que todos vosotros tenéis familiaridad con las variables porque son lo principal de cada lenguaje de programación. Dicho esto, vamos a ver como Java trata las variables.
En primer lugar, antes de utilizarla, una variable se tiene que escribir. En Java la escritura de una variable está compuesta por tres partes: modificadores, tipo e indentificadores.

Los modificadores son una opción y son los que establecen el acceso a las variables, es decir, a los public particulares y protegidos que vimos en el capítulo anterior. Éstos se llaman modificadores de acceso y los hay estáticos, sincronizados y finales. No es importante ponerlos en órden, aunque sí es importante utilizar siempre el mismo órden para que sea legible el código. Estátic también lo vimos: nos permite escribir atributos y métodos constantes que se pueden invocar incluso antes de que un objeto se escriba. Final, en cambio, quiere decir que, cuando se utiliza un valor, éste se puede unir sólo una vez a un campo porque es también una constante. El modificador sincronizado lo dejaremos de lado: basta con indicar que sirve para decir que a un método, en el caso de una multiprogramación (con los thread), se puede acceder a través de una exclusión múltiple, es decir, un thread a la vez.

Los identificadores pueden ser uno o más, están separados por una coma y son nombres que tienen variables. Por ejemplo, la escritura de X en el ejemplo anterior se convertirá en:

ent X;

pero, también puedo escribir más de uno. Por ejemplo, la siguiente escritura se considera válida:

ent X,Y,Z;
doble W=3.12;

Como son atributos de las clases tienen que escribirse dentro de los mismos; escribirlos fuera de ellos se considera un error.
Como se puede ver en el ejemplo, también es posible inicializar una variable en el momento en el que la creamos: símplemente hay que añadir, después del nombre, el signo igual y el valor que toma.
Después de la escritura de la variable y su inicialización, el identificador de la variable, en cualquier lugar que se haya escrito, se entiende como su valor actual, excepto si le damos un nuevo valor. Por ejemplo, si escribo X = 10 me refiero a la variable X y no a su valor, y con el signo igual 10 me refiero a que el nuevo valor de la variable es 10.
Si después escribo:

X = X+1;

con la X a la izquierda del signo igual me refiero a que la variable se llama X, mientras que con la X a la derecha me refiero al valor actual de la variable X. La expresión X+1, entonces, en este caso será

10 + 1 y entonces 11, es decir por X = X + 1, he dicho X = 11;

Provad este pequeño programa que hace unos calculos:

class p
{
ent X,Y,Z;

double W = 3.12;

public double A = 15;

static int B = 101;

private final int C = 2;

protected static boolean D = true;

public p()

{

X= 10 ;

Y= X ;

Z= X + Y ;

System.out.println ("Al'principio tengo: X="+X+", Y="+Y+", Z="+Z);

X= X + 1 ;

Y= Z - X;

System.out.println ("Hago las operaciones: nX= X + 1 ;nY= Z - X;ned resultado:");

System.out.println ("X="+X+", Y="+Y+", Z="+Z);

}

}

class decl

{

public static void main(String[] a)

{
p Prueba=new p();

}
}

Como sabéis, visto que decl es la clase que incluye el main, tendréis que editar el programa en un archivo que se llama decl.java; después, ponedlo en marcha y a ver lo que ocurre. Hay también otros atributos para mostrar el uso de los modificadores.
En el ejemplo vemos que yo creé una clase p y le puse el objeto Prueba, llamando al constructor. Hice esto porque las variables son atributos y, por eso, si no son estáticos, son atributos de un objeto. Tuve que crear un objeto para poder trabajar con sus variables. Hay que acostumbrarse a programar desde esta perspectiva porque los programas Java son todos así. Como el main del programa TIENE que declararse static (y tiene que tener una cadena como parámetro), éste se pone en marcha en ausencia del objeto y, por eso, algunas variables no son estáticas. Si hubiera querido crear solo una clase, hubiese tenido que escribir algo parecido a:

class decl2
{
int X,Y,Z;

// Main
public static void main(String [] a)
{

decl2 Prueba=new decl2();

}

// Constructor

public decl2()
{

X= 10 ;

Y= X ;

Z= X + Y ;

System.out.println ("Al'inicio tengo: X="+X+", Y="+Y+", Z="+Z);

X= X + 1 ;

Y= Z - X;

System.out.println ("Hago las operaciones: nX= X + 1 ;nY= Z - X;ned resultado:");

System.out.println ("X="+X+", Y="+Y+", Z="+Z);

}

}

En este segundo ejemplo, editado y redactado en decl2.java, no se entiende bien cuándo vemos decl2 como clase y cuándo como objeto. Realmente el main está en la clase y en él se crea el objeto. Por tanto se invoca el constructor y dentro de él razonamos en términos de objeto creado. De todas formas, es posible y veréis que el programa funciona también en este caso. Algún día, cuando tengáis más familiaridad con el lenguaje, podréis hacerlo vosostros también. De momento no os lo aconsejo porque es fundamental, llegados a este punto, distinguir bien entre clases y objeto, y esto se consigue fácilmente con mucha experiencia.

Los identificadores Java tienen que empezar por una letra (o con _ o $) seguida por una secuencia larga de caracteres y cifras elegidas a vuestro antojo. Las cifras, codificadas en Unicode, son mucho más numerosas que las letras y que las cifras ASCII utilizadas por otros lenguajes. Lo siento, pero no tengo un mapa completo de los caracteres unicode que dejaros, pero puedo deciros que están incluidos los caracteres griegos, cirílicos, árabes, etc.

Ahora vamos a ver cómo escribir e inicializar un array. La escritura se hace poniéndo un par de corchetes después del tipo:

ent [] vectorDeEnteros;

Los array en Java son casi objetos, sólo que no pueden extenderse para añadirles nuevos métodos. Lo que acabamos de citar es una referencia a un array que, sin embargo, rl lenguaje no ha asignado. Si quiero inicializar el array elemento por elemento, como se hace con los demás lenguajes, tengo que escribir las dimensiones:

ent [] vectorDeEnteros = nuevo ent[100];

A partir de ahora puedo empezar a poner los elementos en el vector, en las posiciones de 0 a 99. Si salgo de estos números, el aparato nos dará unmensaje de excepción del tipo out of range.
Cuando creo, puedo además inicializar un array, basta con escribir:

ent [] vectorDeEnteros = { 1,2,3,10,100,555,0, ….otros valores…};

Además puedo crear unos vectores cuyos elementos son ellos mismos vectores, etc. Esto se consigue de esta forma:

double[] [] matrizIdentidadDeÓrden3 = { { 1.0 , 0.0 , 0.0 } ,
{ 0.0 , 1.0 , 0.0 } ,
{ 0.0 , 0.0 , 1.0 } };

El siguiente programa utiliza los array y lo editaremos en un archivo que se llama vect.java:

clase vect
{

static ent NOMBRE = 0;

static ent APELLIDOS = 1;

static ent PATODÓNALD=0;

static ent GILBERTO=1;

static ent JORGITO=2;

static ent JAIMITO=3;

static ent JUANITO=4;

static ent GUS=5;

static ent COMISARIO=6;

static ent RATÓN=7;

static ent SUPER PATO=8;

static ent PLUTO=9;

static ent ABUELA=10;

static ent GILITO=11;

static Cadena personajes[][] = {
{"Paolino","Pato Donald"},
{"Pietro","Gilberto"},
{"Jorgito","No especificado"},
{"Jaimito","No especificado"},
{"Juanito","No especificado"},
{"Ciccio","De Abuela Donald"},
{"No especificado","Comisario"},
{"No especificado","Ratón Micky"},
{"Tribilín","No especificado"},
{"Pluto","No especificado"},
{"No especificado","Daisy"},
{"No especificado","Gilito"},
};

public static void main(String [] a)
{

ent PersonajeTmp;

ent Número=1;

System.out.println ("Unos personajes de Walt Disney");

PersonajeTmp=PATODÓNALD;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

Número=Número+1;

PersonajeTmp=GILBERTO;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

Número=Número+1;

PersonajeTmp=JORGITO;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

Número=Número+1;

PersonajeTmp=JAIMITO;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

Número=Número+1;

PersonajeTmp=JUANITO;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

Número=Número+1;

PersonajeTmp=GUS;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

Número=Número+1;

PersonajeTmp=COMISARIO;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

Número=Número+1;

PersonajeTmp=PLUTO;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

Número=Número+1;

PersonajeTmp=TRIBILÍN;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

Número=Número+1;

PersonajeTmp=GILITO;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

Número=Número+1;

PersonajeTmp=RATÓN;

System.out.println("Número:"+Número+"tNombre:"+personajes[PersonajeTmp][NOMBRE]+" Apellidos:"+personajes[PersonajeTmp][APELLIDOS]);

System.out.println("HiCe los cálculos "+Número+" personajes, y eran muchos más");

// Éste sí es un programa realmente inútil. El autor.

}
}

Un pequeño comentario sobre el programa. Os habéis dado cuanta de que en el main se establecen unas variables (es posible hacerlo): normalmente se usan sin redactarlas como static porque las variables del main, o de una función, por lo general, no son atributos y, por eso, no están relacionados con el objeto o con la clase, sino sólamente con la función en la que se escriben. En estas definiciones no están incluidos los modificadores porque estos se asocian a las clases.

Llegados a este punto nos queda por ver los tipos compuestos que se pueden fácilmente identificar ahora con las clases. Por ejemplo, si queréis definir el tipo compuesto Complejos, escribiremos:

clase Complejos
{
private double ParteReal;

private double ParteImaginaria;

Complejos (double Re, double Im)
{

ParteReal=Re;

ParteImaginaria=Im;

}

// ahora estableceremos todos nuestros obvios métodos en el nuevo tipo
double démeParteReal()
{
return ParteReal;
};
double démeParteImaginaria()
{
return ParteImaginaria;
};
double calculaMódulo()
{
return (java.lang.Math.sqrt((ParteImaginaria*ParteImaginaria)+ (ParteReal*ParteReal)));
};

}

Para probar, podéis escribir los siguiente(pruebaComplejos.java):

clase pruebaComplejos
{

public static void main (Cadena[] arg)
{
Complejos N=nuevo Complejos(3.0,1.1);

double Re=N.démeParteReal();

double Im=N.démeParteImaginaria();

double mod=N.calculaMódulo();

System.out.println("Número complejo:"+Re+"+i"+Im+" tiene "+mod);

}

}




Operadores



Los operadores del enguaje Java son los mismos que los de los demás lenguajes, además cada nuevo tipo tendrá su proprio método que incluyen nuevos operadores, como vimos en el ejemplo de la clse Complejos.
Analizamos los operadores de acceso a las clases y a los objetos, es decir, simplemente el punto. Si queremos entrar en el campo X del objeto x, simplemente tendremos que escribir x.X, aunque x tenga un método Y(ent valor), nosostros entramos o, mejor en este caso, lo solicitamos escribiendo x.Y(39); Tenemos los operadores aritméticos de siempre: +,-,*,/ y %.
Hay que tener en cuenta también las operaciones son tipadas, es decir, si sumo dos enteros el resultado es un valor entero y así para todas las operaciones, de forma que si tenemos una expresión siempre es posible establecer el tipo de resultado.
Java ejerce un fuerte control sobre los tipos. De hecho, no es posible asignar un carácter e un entero, lo que es posible en el lenguaje C, y además es imposible asignar un double a un float sin un casting explícito. El casting obliga a un valor de un tipo a tener un tipo distinto. Si escribo 5, me refiero a un entero, mientras que si hago un cast a float me refiero a la versión de 5 real y para hacerlo tendré que escribir(float) 5.
De esta forma puedo asignar los enteros a reales y de reales double a relaes float. Pensemos, por ejemplo en:

double v1=10.0;
float v2;
ent v3=5;

y pensemos en las siguientes asignaciones equivocadas:

v2=v1;
v1=v3;

Si hacemos unos cast, se convierten en exactas también para Java:

v2=(float) v1;
v1=(double) v3;

Hay que notar la división de los enteros que en otros lenguajes da un entero. Por lo tanto, si queremos el número real que resulta de la división de los dos números enteros x e y, antes hay que transformarlos en números reales:

float resultado= (float ) x / (float) y;

Para las cadenas hay un operador de encadenamiento:

cadena a="Pietro " ;
Cadena b= a + "Castellu";
Cadena b+="cci"

El resultado será Pietro Castellucci. El operador es el signo +. En un momento dado, utilizamos una asignación particular, es decir, += que es una abreviación. Si tengo que escribir a=a+1; puedo abreviar y escribir a+=1, que es lo mismo. Lo mismo vale para cada operador binario. El operador + cuelga de una cadena también caracteres y números, pensemos en las salidas de los ejemplos anteriores en los que escribíamos, por ejemplo:

System.out.println("Número complejo:"+Re+"+i"+Im+" tiene módulo "+mod);

esto os puede parecer raro, sobre todo si consideramos que dijimos que las expresiones Java están bien caracterizadas por los tipos, a diferencia del C. Esto ocurre, sin embargo, porque el sistema hace unas conversiones implícitas de tipos primitivos y objetos en cadenas. Por ejemplo, si establecemos cualquier objeto y lo hacemos con un método toString(), el sistema tendrá que trabajar con cadenas y con este objeto solicitará automáticamente el método toString().

Además Java ofrece otros cuatro operadores que son unas abreviaciones: dos son de incremento de variables y dos de incremento. Si X es una variable puedo escribir:

X++
++X
X--
--X

Esto quiere decir: primero evalua X y luego incrementa X, primero incrementa X y luego evalua X, primero evalua X y luego disminuye X y , por último, primero disminuye X y luego evalúa X. Esto quiere decir que la expresión X++ es un mando de asignación, pero también una expresión que devuelve un resultado que, en este caso, es X antes de que se incremente.

Por ejemplo:

X=10;
Y=X++;

dará como resultado X=11 e Y=10. Intendad editar y poner en marcha lo siguiente clase incdec

{

public static void main(Cadena [] a)
{

ent X,Y,Z,W,V;

X=10;

System.out.println("X="+X);

Y=X++;

System.out.println("Y=X++: tengo X="+X+",Y="+Y);

Z=++Y;

System.out.println("Z=++Y: tengo Z="+Z+",Y="+Y);

W=Z--;

System.out.println("W=Z--: tengo W="+W+",Z="+Z);

V=--W;

System.out.println("V=--W: tengo V="+V+",W="+W);

}
}

Otros operadores son los de comparación, es decir:

> mayor de, x>y nos da verdadero si x es mayor que y, en caso contrario, nos da falso

>= mayor o igual a, x>=y nos da verdadero si x es mayor o igual a y, en caso contrario nos da falso

< menor de, x<y nos da verdadero si x es menor de y, en caso contrario, nos da falso

<= menor o igual a, x<=y nos da verdadero si x es menor o igual a y, en caso contrario, nos da falso

== igual a, x==y nos da verdadero si x es igual a y, en caso contrario, nos da falso

!= diferente, x!=y nos da verdadero si x es diferente de y, en caso contrario, nos da falso

Tenemos también los operadores lógicos &&, || y !, que representan la conjunción y, la disjuntiva o y el no: Establecidos los valores booleanos x e y , x && y será verdadera si x e y lo son también; será falsa si no lo son (si las dos son falsas o si una es verdadera y la otra falsa).
x || y sará vedadera si x o y o los dos son verdaderas (será falsa sólo si los dos son falsos). !x será verdadera si x es falsa, mientras será falsa si x es verdadera.
Tenemos los operadores binarios orientados hacia los bit:

&, AND bit a bit
| , OR bit a bit
^, OR EXCLUSIVO, bit a bit
y los shift, >>, <<, >>>.

Estas operaciones binarias son muy útiles para construir las matrices.

El último operador es el condicional que nos permite definir expresiones con dos diferentes resultados según un valor booleano.
Pongamos el siguiente ejemplo:

ent ValorAbsoluto = ( a<0 ? -a : a );

ValorAbsoluto tendrá el valor -a si a es negativo o si a es positivo o nulo.
Llegados a este punto, podemos escribir todas las expresiones que queramos en lenguaje Java.


Instrucciones



Estamos preparados para ver los constructores principales del lenguaje Java. Ya vimos los comentarios, que no se pueden ocultar, es decir, que el siguiente comentario no es posible: /* +Éste es seguramente un comentario /* Éste también lo es */ */ Sin embargo, se pueden introducir comentarios de una línea en los comentarios de más de una línea porque son distintos. Por ejemplo, es posible escribir lo siguiente: /* Éste es seguramente un comentario // Éste también lo es */ aunque realmente resulte bastante inútil. Las primeras instrucciones de Java que vamos a ver son las instrucciones de declaración, que son las declaraciones de variables locales. Se utilizan para declarar variables y darles un posible valor inicial. Estas instrucciones ya las vimos y se parecen a las declaraciones de los atributos, excepto por la falta de los modificadores. Las variables locales, antes de ser utilizadas, se tienen que inicializar.
Las variables locales se pueden declarar en un punto cualquiera de un bloque y no necesariamente al inicio, además existen sólo en los bloques en los que se declaran. Un bloque es como una instrucción, lo único es que empieza por { y acaba por }, y en él puede tener muchas instrucciones, incluso posiblemente de otros bloques.

{
instrucción 1;
instrucción 2;
….
instrucción j-1;
{
subinstrucción1;
subinstrucción2;
…..
subinstrucción;
}; // es la instrucción j
instrucción j+1;
….
instrucción n;
}// Este bloque puede ser el cuerpo de un método o un bloque
Pensad en el método:
void tribilín()
{
ent j=0;
{
ent k=0;
k++; // instrucción A
};
j++; // instrucción B
k++; // instrucción C
}

La instrucción A no da problemas porque usa una variable local que está inicialidada, declarada en su mismo bloque.
Con la instrucción B ocurre lo mismo, mientras la instrucción C está equivocada porque la variable que utiliza se ha declarado en un bloque entero y no se puede ver externamente. Si en el bloque interno hubiera escrito j++; no tendría ningún problema porque la variable j se habría declarado en un bloque externo. (Dentro se ve lo que hay fuera, pero fuera no se puede ver lo que hay dentro, lo cual ocurre en todos los lenguajes de programación por bloques).
Acabamos de ver en el ejemplo que también j++ es tanto una instrucción como una expresión, como su otra forma e ++j, y es su imagen especular de disminución. Hay otras operaciones que se pueden tener en cuenta a la hora de analizar las instrucciones. Se trata tanto de la implementación de los métodos que pueden devolver o no un valor, como de las instrucciones de creación de objetos, las que llevan new. Por ejemplo, new Object(), es una instrucción correcta.
Otra instrucción muy parecida a una expresión es la instrucción de asignación, la del tipo:

NombreVariable = expresión;

Por lo tanto, hasta ahora hemos visto las seis instrucciones:

Declaración de una variable local;
Bloque;
Formas de incremento y disminución de las variables, prefijas y postfijas;
Creación de los objetos;
Solicitud de los métodos;
Asignación de las variables;

Todas las instrucciones terminan por ;

Las demás instrucciones se llaman constructos y son muy parecidas a las de los demás lenguajes de programación. Las vamos a ver detalladamente.

Instrucción condicional
if (EXPBOOL) IST
Esta instrucción pone en marcha la instrucción llamada IST que puede ser una cualquier instrucción del lenguaje sólo si la expresión booleana EXPBOOL es verdadera, de lo contrario se salta. Una variedad es la en que pone en marcha otra instrucción si EXPBOOL es falsa, es:

if (EXPBOOL) IST
else
IST2

Fijaos que IST y IST2 son instrucciones generales, por lo tanto también los bloques o las demás instrucciones condicionales. En este último caso hablamos de if ocultos.

Instrucción switch

Switch (EXP)
{
case CST11: …. :case CST1n: IST1
case CST21: …. : case CST2n: IST2
….
case CSTm1: …. : case CSTmn: ISTm
default ISTm+1;
};

Si EXP es una expresión, CSTij son unas constantes del mismo tipo que la expresión. EXP y ISTi son unas instrucciones.
La instrucción evalúa EXP, y compara el resultado con las constantes de los case; si encuentra otro igual, pone en marcha la instrucción correspondiente. Si, en cambio, no encuentra ninguna constante igual, pone en marcha la instrucción después del default, lo que es una opción. En el caso de que esté ausente y ningún case tenga la constante igual al valor de EXP, se salta el switch.
Analizamos, por ejemplo, el siguente mando:

switch (5+1)
{
case 6 : System.out.println ("Muy bien");
default : System.out.println ("Burrp, es seis");
};

Instrucción for for (exp de inicialización; exb booleana; exp de incremento) ISTR
pone en marcha la instrucción ISTR que es un número de veces igual a los valores contenidos en un intervalo. Normalmente la instrucción de inicialización pone en marcha una variable en un valor; la variable se incrementa (o disminuye) a partir de la instrucción de incremento y en la expresión booleana se controla que la variable tenga los valores que queremos. En efecto, si la expresión booleana es falsa, enseguida se sale del ciclo for.
Voy a poner un ejemplo: quiero inicializar los valores de un vector de 100 enteros todos a cero. En lugar de escribir 100 asignaciones, escribiré:

ent v = new ent[100];
for (ent e = 0 ; e<100; e++) v[e] = 0 ;

Como acabamos de ver la variable también se puede declarar en la instrucción de inicialización. De esta forma, sólo se puede ver en el for.

Instrucción while
while (EXPBOOL) IST
Pone en marcha IST simulando que EXPBOOL es verdadera, por ejemplo, la inicialización del ejemplo anterior se puede llevar a cabo con el while de la siguiente forma:

ent v = nuevo ent[100];
ent e=0;
while (e<100) {
v[e]=0;
e+=1;
};

o de forma comprimida, aprovechando el incremento de forma comprimida:

ent v = nuevo ent[100];
ent e=0;
while (e<100) v[e++]=0;

Instrucción do-while do IST while (EXPBOOL);
ES como el while, sólo que antes ejecuta la instrucción y luego controla el EXPBOOL, de nuevo la inicialización precedente se convierte en:

ent v = nuevo ent[100];
ent e=0;
do {
v[e]=0;
e+=1;
} while (e<100);

o también de forma todavía más comprimida:

ent v = nuevo ent[100];
ent e=0;
do v[e++] = 0 while (e<100);

Etiquetas
Es posible poner etiquetas a las instrucciones, como ocurre con el código assembler. Esto resulta muy útil en combinación con las instrucciones de break y de continue:

etiqueta: instrucción;

instrucción de break
La instrucción de break se utiliza para salir de un bloque o de un switch; cuando se encuentra un break se sale del bloque más interno, mientras que si se pone una etiqueta, se sale hasta donde la etiqueta se ha declarado.

Ejemplo:

{
while ( COND )
{
while (COND2)
{
if (ALGO) break;
}
}
}
En este caso se sale del while interior, mientras:
{
tribilín: while ( COND )
{
while (COND2)
{
if (ALGO) break tribilín;
}
}
}

se sale de los dos while.

Instrucción de continue
En un ciclo se salta todas las instrucciones que le siguen y evalúa directamente la expresión booleana, por ejemplo:

while (Condición)
{
instrucciones;
if (GolpeDeEfecto) continue;
otras instrucciones;
};

Se entra en el ciclo, se ponen en marcha las instrucciones. Si GolpeDeEfecto es verdadero, salta otras instrucciones y llega a evaluar Condición. Si ésta también es verdadera, continúa el ciclo poniendo en marcha las instrucciones, etc..

Instrucción de return
Produce la conclusión de la ejecución del método en el que se encuentra y el retorno a la llamada. Si el método es void basta con escribir return, si no tiene que contener una expresión del mismo tipo del método, por ejemplo

ent tribilín()
{
return 10;
}

con la instrucción return es posible también bloquear la puesta en marcha de un constructor o de un método static.

Con esto acabamos nuestro examen de las instrucciones. Ahora estamos preparados para construir cualquier aplicación a consola.
Pongamos un par de ejemplos: empecemos escribiendo un pequeño programa que imprima los primeros números, los menores de 500 de la famosa serie de Fibonacci. Para los que no la conozcan, la serie de Fibonacci es una secuencia infinita de números cuyos dos primeros elementos son: 1, 1, y los demás elementos se calculan como la suma del e-1 ésimo número y del e-2 ésimo, formalmente, reconociendo Fibo come una función:

Fibo ( e ) = Fibo ( e - 1 ) + Fibo ( e - 2 );

El programa que hay que escribir en Fibo.java es el siguiente:

class Fibo
{

public static void main (Cadena[] args)

{

ent bajo=1, alto=1;

// ent alto=1;

System.out.println (bajo);

while (alto<500)
{

System.out.println(alto);

alto+=bajo;

bajo = alto - bajo;

};

}

}

Para que os entrengáis, podéis intentar hacer un programa que calcula 10 ! , sabiendo que 1! = 1 y que establecido n entero, n! = n * ((n-1)!). La solución se encuentra en el archivo Fatt.java.
Ahora, intentamos escribir nuetra criba de Eratóstenes hecho en casa, es decir, una forma para calcular todos los números primos hasta un número establecido, digamos 100;
El algoritmo procede así,

1 es un número primo.
2 es un número primo, le quito sus múltiplos
3 es un número primo, le quito sus múltiplos

etcétera hasta encontrar mi máximo.

clase Eratóstenes
{
static ent MÁX=1000;

ent [] números = nuevo ent[MÁX];

boolean [] primos = nuevo boolean[MÁX];

public Eratóstenes()
{

ent e;

for (e=0;i<MAX;e++)
{
números[e]=e+1;

primos[e]=verdaderos;

};

}

void elMul(ent a)
{

for (ent j=2;j*a<=MÁX;j++)
primos[(j*a)-1]=falso;

}

ent siguiente(ent n)
{
ent tmp=n;

while (!primos[tmp]) {
tmp++;
if (tmp>=MÁX) break;
}

return tmp+1;

}

void calculaPrimos()
{
ent núm=2;

while (núm<=MÁX)
{
elMúl(núm);
núm=siguiente(núm);
};

}

void escribaPrimos()

{

System.out.println("Los números primos hasta "+MÁX+" son:");

for (ent e=0; e < MÁX ; e++)
if (primos[e]) System.out.print(números[e]+" ");

}

public static void main(Cadena[] args)
{

Eratóstenes e = nuevo Eratóstenes();

e.calculaPrimos();

e.escribaPrimos();

}

}



Indicaciones sobre las excepciones y sobre los thread


Las excepciones son una forma clara para controlar los errores sin confundir el código con muchas instrucciones de control del error. Cuando se verifica un error se pone en marcha una excepción que, si se recibe enseguida, nos permite gestionar un error. De lo contrario, el soporte lleva a cabo como ejecución de Java, un íter de default.
En Java hay una clase que se llama Exception, y las excepciones son objetos que pertenecen a esta clase. Por eso, se pueden trabajar como verdaderos componentes del lenguaje.
Vamos a ver cómo es posible crear una excepción.
Hay que crear una clase que amplía Throwable, o mejor Exception , que es una extensión de Throwable. Supongamos que queremos crear una excepción para decir que utilizamos una cadena vacía: tendremos que escribir:

public clase ErrorCadenaVacía amplía Exception
{
ErrorCadenaVacía()
{
super("Cuidado, estás utilizando una cadena que no ha sido inicializada");
}
}

Esta clase tiene que estar en un archivo que se llama como la clase, es decir, ErrorCadenaVacía.java Después de haberla creado, necesitaremos una forma para hacerla trabajar, es decir, para evidenciar la situación de error que, ya que estamos, espero que alguien recoja. Las excepciones trabajan con la instrucción throw que tiene que estar en un método que, a su vez, se tiene que declarar con un cláusola throws. Por ejemplo, en nuestro caso, si quiero crear un método para imprimir la cadena que controla incluso el error, escribiré en mi clase:

public void Imprimir (Cadena a)
throws ErrorCadenaVacía /* ß Esto quiere decir que esta función puede poner en marcha una excepción del tipo ErrorCadenaVacía*/
{
if (a==null) throw nuevo ErrorCadenaVacía();
else System.out.println(a);
}

Entonces, llegados a este punto, el método Imprimir enviará a la pantalla la cadena transformada en parámetro y dará un excepción de tipo ErrorCadenaVacía si el puntero era nulo.
La excepción que damos nosotros se llama excepción controlada y tiene que ser obligatoriamente gestionada, mientras las que da Java no necesariamente tienen que ser recogidas y gestionadas.
Ahora vamos a ver como recoger las excepciones, por ejemplo, nuestra ExcepciónCadenaVacía.
Las excepciónes se recogen cuando se solicitan los métodos que se declaran con la cláusula throws. Para recogerlas hay que implementar el método en bloques try que tienen la siguiente sintaxis:

try
BLOQUE // Éste es un bloque peligros porque puede poner en marcha unas excepciones. catch (Tipo de Excepción que hay que coger)
BLOQUE // Éste es un bloque de restablecimiento. catch (Tipo de Excepción que hay que coger)
BLOQUE // Éste es un bloque de restablecimiento.
….
finally
BLOQUE

El corpus de esta instrucción se ejecuta hasta el final o hasta que aparezca una excepción. En caso de excepción, se analizan las cláusulas catch para ver si existe un administrador para esa excepción o para una de sus superclases. Si ninguna cláusula catch recoge esa excepción, ésta vuelve a lanzarse en el método que la ha provocado (que la ha ejecutado).
Si en el try hay una cláusula finally, su código se pone en marcha después de que se hayan completado todas las demás operaciones del try, independientemente de que ésta haya ejcutado una excepción o no. Por ejemplo, nuestro método Imprimir se puede invocar así:

Si X es la cadena que hay que imprimir:

try {Imprimir(X);}
catch (ErrorCadenaVacía e)
{System.out.println ("Lo siento");}

En este caso, si X es nulo, se pondrá en marcha la excepción y se recogerá; después se imprimirá la cadena Lo siento, si no X. Si escribiera Imprimir(X) fuera de la try, saldría error porque las excepciones que yo he causado tienen que ser recogidas. Esto obliga al programador a escribir código "bueno". Las excepciones de Java, en cambio, se pueden coger o no.
El ejemplo siguiente recoge el HolaMundo del primer capítulo que, si invocado sin parámetros, daba una excepción de ArrayIndexOutOfBoundsException, que, este vez, se gestiona;

clase HolaMundo
{

public static void main(Cadena[] args)
{

System.out.print ("Hola Mundo, soy el primer programa en Java");

Cadena Nombre;

Cadena Apellidos;

try {Nombre=args[0];}
catch (ArrayIndexOutOfBoundsException e)
{Nombre="No has introducido tu Nombre";}

;
try {Apellidos=args[1];}
catch (ArrayIndexOutOfBoundsException e)
{Apellidos="No has intruducido tus Apellidos";}
;

System.out.println ("de "+Nombre+" "+Apellidos);
}
}

Intenten ponerlo en marcha de las siguientes formas:

java HolaMundo Nombre Apellidos
java HolaMundo Nombre
java HolaMundo

y a ver lo que pasa. Hagan lo mismo con el HolaMundo del primer capítulo.



El paquete java.lang



El Paquete lang

Este paquete lo vimo antes. Ahora, sin embargo, analizaremos algunas funciones que antes no vimos. En primer lugar, hay que decir que éste es uno de los paquetes más importantes de la API Java. Abarca muchísimas clases e interfaces fundamentales para la programación Java, tanto que este paquete se incluye atomáticamente en nuestros programas. Su contenido es::

Intefaces
Cloneable
Comparable
Runnable

Clases
Boolean
Byte
Character
Character.Subset
Character.UnicodeBlock
Class
ClassLoader
Compiler
Double
Float
InheritableThreadLocal
Integer
Long
Math
Number
Object
Package
Process
Runtime
RuntimePermission
SecurityManager
Short
String
StringBuffer
System
Thread
ThreadGroup
ThreadLocal
Throwable
Void

Excepciones
ArithmeticException
ArrayIndexOutOfBoundsException
ArrayStoreException
ClassCastException
ClassNotFoundException
CloneNotSupportedException
Exception
IllegalAccessException
IllegalArgumentException
IllegalMonitorStateException
IllegalStateException
IllegalThreadStateException
IndexOutOfBoundsException
InstantiationException
InterruptedException
NegativeArraySizeException
NoSuchFieldException
NoSuchMethodException
NullPointerException
NumberFormatException
RuntimeException
SecurityException
StringIndexOutOfBoundsException
UnsupportedOperationException

Errores
AbstractMethodError
ClassCircularityError
ClassFormatError
Error
ExceptionInInitializerError
IllegalAccessError
IncompatibleClassChangeError
InstantiationError
InternalError
LinkageError
NoClassDefFoundError
NoSuchFieldError
NoSuchMethodError
OutOfMemoryError
StackOverflowError
ThreadDeath
UnknownError
UnsatisfiedLinkError
UnsupportedClassVersionError
VerifyError
VirtualMachineError

En el primer capítulo vimos las clases que incluyen los tipos primitivos incluidos en este paquete. En este apartado analizaremos unas clases que hacen cosas más complejas.
La primera clase que analizaremos es la clase System, que relacciona nuestro programa Java con el sistema en el que se pone en marcha. En primer lugar, la clase System incluye tres atributos estáticos que son:

static PrintStream err static InputStream in static PrintStream out

Estos programas representan respectivamente el error estándar, el input estándar y el output estándar (que ya utilizamos). Son atributos particulares porque son de tipo clase, por eso se pueden utilizar como referencia para capturar los métodos de las clases, por ejemplo, en la escritura:

System.out.println("Hola");

Se invoca el método println(String) de la classe PrintStream, porque out es de tipo PrintStream. En nuestros ejemplos, utilizamos indiferentemente las expresiones:

System.out.println("Hola");
System.out.println(verdadero);
System.out.println(10);
System.out.println('C');

En general, en Java esto no es posible porque un método se invoca a través de un parámetro formal. Esto no es una excepción. De hecho, invocar el método println con todos estos tipos de datos distintos es posible porque PrintStream incluye todos los métodos println utilizados con el parámetro formal adecuado. Así ésta incluye:

void println()
void println(boolean x)
void println(char x)
void println(char[] x)
void println(double x)
void println(float x)
void println(int x)
void println(long x)
void println(Object x)
void println(String x)

los mismos métodos print, y por supuesto, otros.

Lo mismo vale para err, que es también parecido a un out del tipo PrintStream. Éste se usa para evidenciar los errores de programa. Es bastante fácil encontrar expresiones como las siguientes en los programas:

try {System.out.println(cadena+" vs "+otracadena+" = " +cadena.compareTo(otracadena));}
catch (nullPointerException e)
{System.err.println("ERROR: La segunda cadena es nula");};

En cambio, el atributo in es del tipo InputStream, y representa, como dijimos antes, el estándar input.
Los métodos para actuar sobre él serán, entonces, unos read:

abstract int read()
int read(byte[] b)
int read(byte[] b, int off, int len)

Como es del tipo InputStream, lee unos byte. Si queremos que lea otras cosas tenemos que especializarlo en esta otra cosa. En el siguiente ejemplo, que teclearemos en un archivo que se llama StandardIO.java, le haremos leer enteras líneas.

import java.io.*;
class StandardIO
{
public static void main(String[] temas)
{

System.out.println("Incluye tus input, teclea end [ENVÍO] para salir");

InputStreamReader a=new InputStreamReader(System.in);

BufferedReader IN=new BufferedReader(a);

String s=new String();

while(s.compareTo("end")!=0)
{

try {s=IN.readLine();}
catch (IOException e)
{s="ERROR DE LECTURA";};

System.out.println("Leído: "+s);

}
}
}

Vamos a ver algunos métodos de la clase System:

static long currentTimeMillis(), este método nos devuelve el tiempo en milisegundos
static void exit(int status), este método determina como salir de Java Virtual Machine, con un
código .
static void gc(), Java coloca tantos objetos, y los descoloca, cuando ya no se usan y se necesita nueva
memoria. Para hacerlo, utiliza un Garbage Collector , y este método pone en marcha el garbage collector en cualquier momento para liberar la memoria precedentemente establecida por el programa que todavía no se ha utilizado. Puede resultar muy útil en aplicaciones muy grandes.
static String getenv(String name), nos devuelve una cadena que incluye informacciones con respecto al
sistema con el que se pone en marcha el programa. El método declarado es deprecated en las últimas Documentaciones on line del Java Development Kit porque el método pronto desaparecerá. Es una de las primeras versiones del lenguaje y todavía aparece porque es compatible con el viejo software.
static Properties getProperties() , es el nuevo método para obtener informaciones sobre la propriedad del
sistema.
static String getProperty(String key), como antes, lo único es que recoge informaciones
específicas con respeto a key
static String getProperty(String key, String def)
static void load(String filename) , carga en la memoria el código incluido en filename, que es una
biblioteca dinámica.
static void loadLibrary(String libname), carga la biblioteca de sistema mencionada por libname
static String mapLibraryName(String libname), hace un mapa de una biblioteca en una cadena que la representa.

Hay métodos para volver a asignar los estándars input, output y err, en otros flujos, por ejemplo un archivo.

static void setErr(PrintStream err)
static void setIn(InputStream in)
static void setOut(PrintStream out)

Los siguientes métodos reparan las propiedades del sistema.

static void setProperties(Properties props)
static String setProperty(String key, String value)

Utilizamos unos objetos de tipo Properties y ahora veremos cómo están hechos. Se trata de unas especializaciones de cuadros hash de java y son, en sustancia, unos cuadros que incluyen una serie de parejas Clave - Valor. (En realidad, no son precisamente esto, sino que son unas estructuras muy utilizadas en informática para contener los datos. Pero a nosotros nos interesa verlas así de momento). En particular, las Properties del sistema son:
Clave Descripción del valor asociado
java.version Versión del ambiente de Java Runtime
java.vendor Distribuidor del ambiente de Java Runtime
java.vendor.url URL del destribuidor de Java
java.home Directory donde está instalado Java
java.vm.specification.version Versión de las especificaciones de Java Virtual Machine
java.vm.specification.vendor Distribuidor de las especificaciones de Java Virtual Machine
Nombre de las especificaciones de Java Virtual Machine
java.vm.version Versión de la implementación de Java Virtual Machine
java.vm.vendor Distribuidor de la implementación de Java Virtual Machine
java.vm.name Nombre de la implementación de Java Virtual Machine
java.specification.version Versión del ambiente de Java Runtime
java.specification.vendor Distribuidor del ambiente de Java Runtime Java Runtime
java.specification.name Nombre del ambiente de Java Runtime
java.class.version Versión de las clases de Java
java.class.path Pathname de las clases de Java
os.name Nombre del Sistema Operativo
os.arch Arquitectura del Sistema Operativo
os.version Versión del sistema Operativo
file.separator Separador del Archivo ("/" en UNIX, "" en Windows)
path.separator Separador de Path (":" en UNIX, ";"en Windows)
line.separator New Line ("n" en UNIX y Windows)
user.name Account name del usuario
user.home Home directorio del usuario
user.dir Working directorio del usuario



Para eso, podemos escribir un pequeño programa que nos informe sobre el sistema como el siguiente que hay que editar en un archivo que se llama Sistema.java
import java.io.*;

public class Sistema
{

public static void main(String[] arg)
{

// Cambio el estándar output, uso el archivo Sistema.txt

File outFile=new File("Sistema.txt");

FileOutputStream fw;
try {fw=new FileOutputStream(outFile) ;}
catch (IOException e)
{fw=null;};


PrintStream Output=new PrintStream(fw);

System.setOut(Output);


// Escribo en el nuevo estándar output:

// Tiempo:
long tiempo=System.currentTimeMillis();

System.out.println("Tiempo en milisegundos: "+tiempo);

long t1=tiempo/1000;

System.out.println("Tiempo en segundos: "+t1);

long sec=t1%60;

long t3=t1/60;

long min=t3%60;

long t4=t3/60;

System.out.println("Tiempo en horas h"+t4+" m"+min+" s"+sec);

System.out.println("nEs el tiempo pasado del 1/1/1970 hasta ahora.n");

// Propiedad del sistema:

System.out.println("nPropiedad del sistema:n");
String tmp;

System.out.println("ntJAVAn");

tmp=System.getProperty("java.version ");
System.out.println("Versión del ambiente de Java Runtime: "+tmp);

tmp=System.getProperty("java.vendor");
System.out.println("Distribuidor del ambiente di Java Runtime: "+tmp);

tmp=System.getProperty("java.vendor.url");
System.out.println("URL del distribuidor de Java: "+tmp);

tmp=System.getProperty("java.home");
System.out.println("Directorio donde está instalado Java: "+tmp);

tmp=System.getProperty("java.vm.specification.version");
System.out.println("Versión de las especificaciones de Java Virtual Machine: "+tmp);

tmp=System.getProperty("java.vm.specification.vendor");
System.out.println("Distribuidor de las especificaciones de Java Virtual Machine: "+tmp);

tmp=System.getProperty("java.vm.specification.name");
System.out.println("Nombre de las especificaciones de Java Virtual Machine: "+tmp);

tmp=System.getProperty("java.vm.version");
System.out.println("Versión de la implementación de Java Virtual Machine: "+tmp);

tmp=System.getProperty("java.vm.vendor" );
System.out.println("Distribuidor de la implementación de Java Virtual Machine: "+tmp);

tmp=System.getProperty("java.vm.name");
System.out.println("Nombre de la implementación de Java Virtual Machine: "+tmp);

tmp=System.getProperty("java.specification.version");
System.out.println("Versión del ambiente de Java Runtime: "+tmp);

tmp=System.getProperty("java.specification.vendor");
System.out.println("Distribuidor del ambiente de Java Runtime Java Runtime: "+tmp);

tmp=System.getProperty("java.specification.name" );
System.out.println("Nombre del ambiente de Java Runtime: "+tmp);

System.out.println("ntCLASESn");

tmp=System.getProperty("java.class.version");
System.out.println("Versión de las clases de Java: "+tmp);


tmp=System.getProperty("java.class.path");
System.out.println("Pathname de las clases de Java: "+tmp);

System.out.println("ntSISTEMA OPERATIVOn");


tmp=System.getProperty("os.name");
System.out.println("Nombre del Sistema Operativo: "+tmp);


tmp=System.getProperty("os.arch");
System.out.println("Arquitectura del Sistema Operativo: "+tmp);


tmp=System.getProperty("os.version");
System.out.println("Versión del sistema Operativo: "+tmp);

tmp=System.getProperty("file.separator");
System.out.println("Separador del Archivo: "+tmp);


tmp=System.getProperty("path.separator");
System.out.println("Separador del Pathname: "+tmp);


tmp=System.getProperty("line.separator");
System.out.println("New Line: "+tmp);

System.out.println("ntUSUARIOn");

tmp=System.getProperty("user.name");
System.out.println("Account name del usuario: "+tmp);

tmp=System.getProperty("user.home");
System.out.println("Home directory del usuario: "+tmp);

tmp=System.getProperty("user.dir");
System.out.println("Working directory del usuario: "+tmp);


}

}

Puesto en marcha en mi sistema, el output fue (Sistema.txt):

Tiempo en milisegundos: 956241233430
Tiempo en segundos: 956241233
Tiempo en horas h265622 m33 s53

Es el tiempo transcurrido del 1/1/1970 hasta ahora.

Propiedad del sistema:

JAVA

Versión del ambiente de Java Runtime: null
Distribuidor del ambiente de Java Runtime: Sun Microsystems Inc.
URL del distribuidor de Java: http://java.sun.com/
Directorio donde está instalado Java: C:PROGRAMASJAVASOFTJRE1.3
Versión de las especificaciones de Java Virtual Machine: 1.0
Distribuidor de las especificaciones de Java Virtual Machine: Sun Microsystems Inc.
Nombre de las especificaciones de Java Virtual Machine: Java Virtual Machine Specification
Versión de la implementación de Java Virtual Machine: 1.3.0rc1-S
Distribuidor de la implementación de Java Virtual Machine: Sun Microsystems Inc.
Nombre de la implementación de Java Virtual Machine: Java HotSpot(TM) Client VM
Versión del ambiente de Java Runtime: 1.3
Distribuidor del ambiente de Java Runtime Java Runtime: Sun Microsystems Inc.
Nombre del ambiente de Java Runtime: Java Platform API Specification
CLASSI
Versión de las clases de Java: 47.0
Pathname de las clases de Java: .
SISTEMA OPERATIVO

Nombre del Sistema Operativo: Windows 95
Arquitectura del Sistema Operativo: x86
Versión del sistema Operativo: 4.0
Separador del Archivo:
Separador del Pathname: ;
New Line:
USUARIO

Account name del usuario: pietro
Home directory del usuario: C:WINDOWSProfilesPietr000
Working directory del usuario: D:LavoroHTMLpointcorsoesempicap3lez6
Otra clase muy importante del paquete java.lang di Java es la clase Object. Ésta es la clase desde la que se crean todas las demás clases de Java, es decir, cualquier otra clase de Java es una extensión de la clase java.lang.Object. La class Object no incluye ninguna variable, sino que incluye 11 métodos que se heredan de todas las demás clases de java y pueden ser utilizadas en cualquier objeto fijado en Java, entre las que:
clone(), que crea una copia del objeto idéntica a la de la que invoca el método. En este caso hay que fijarse en que el mismo programa Java es un Objeto, por eso, se pueden crear un número arbitrario de programas todos idénticos. Para que se pueda invocar el método clone() de un objeto, este tiene que implementar la interfaz Cloneable .
getClass(), devuelve un Objeto de tipo Class que representa la clase a la que pertenece el objeto cuyo método fue solicitado.
toString(), transforma el objeto en una cadena. Este método tiene que ser escrito otra vez en los objetos creados por el usuario, pero es muy útil.

Pensemos en la escritura Cadena suma="Sumando"+10+" y "+11+" tengo "+(10+11);
Creamos una cadena usando unas cadenas y unos int. De forma automática, en este caso Java invoca el método toString() de la clase correspondiente que lo contiene. Esto ocurre en cada expresión que abarca cadenas y objetos como "Cadena"+Objeto.

La otra clase del paquete a la que nos referimos antes es Class y representa las clases del lenguaje. Es muy importante porque tiene más de treinta métodos que sirven para gestionar las clases a runtime, lo que es imprenscindible en los demás lenguajes de programación. Objetos de este tipo, llamados descriptores de clase, aunque sean ellos mismos descriptores de interfaces, se crean y se asocian automáticamente a los objetos a los que se refieren.
Objetos de tipo Class, Object y otros tipos, son muy importantes si son a runtime porque permiten gestionar el programa que se está poniendo en marcha como si fuera una colección de datos sobre los que es posible trabajar.
Java es un lenguaje de potencialidad impresionante. Si pensamos en java.lang, hay una clase que se llama Compiler que incluye métodos para redactar fuentes Java. Hay otras clases como ClassLoader, Runtime... que permiten cargar nuevas clases a runtime, ponerlas en marcha, y modificar el programa mismo mientras está trabajando. Potencialmente, es posible escribir en Java partiendo del código que se automodifica (que evoluciona).
Llegados a este punto para terminar la explicación de java.lang, entre otras cosas porque verlo de forma detallada es demasiado complicado y sin duda está fuera de los fines de nuestro curso, nos basta con saber que existe y que hace cosas que para los otros lenguajes de programación es pura fantasía o, como mínimo, es imposible o dificilísimo trabajar a niveles altos.
Antes de acabar descrivo brevemente la clase java.lang.Match (diferente de la clase java.math).
Esta clase sirve para hacer cálculos matemáticos y tiene dos atributos:

static double E , es la e de Eulero
static double PI, es la PI griega

Los métodos son obviamente todas las funciones matemáticas calculables, entre las que:

Los valores absolutos de valores double, float, int e long:
static double abs(double a)
static float abs(float a)
static int abs(int a)
static long abs(long a)
Las funciones trigonométricas

static double acos(double a) - arcocoseno
static double asin(double a) - arcoseno
static double atan(double a) - arcotangente
static double cos(double a) - coseno
static double sin(double a) - seno
static double tan(double a) - tangente
Transformaciones de ángulos

static double toDegrees(double angrad) - convierte radiantes en grados
static double toRadians(double angdeg) - convierte grados en radiantes
static double atan2(double a, double b) - convierte coordinadas cartesianas (b,a) en coordinadas polares (r,theta)
Funciones exponenciales y logarítmicas

static double exp(double a) - y elevado a la a.
static double log(double a) - logaritmo en base y de a
Máximos y mínimos entre valores double, float, int e long

static double max(double a, double b)
static float max(float a, float b)
static int max(int a, int b)
static long max(long a, long b)
static double min(double a, double b)
static float min(float a, float b)
static int min(int a, int b)
static long min(long a, long b)
Potencias y raíces

static double pow(double a, double b) - calcula a elevado a la b, notar que si b es <1, esta es
una raíz(1/b)-esima de a
static double sqrt(double a) - calcula la raíz cuadrada de a.
Números pseudocasuales

static double random() - da un numero casual entre 0 y 1
Redondeos

static double rint(double a) - parte entera baja de a, es un entero
static long round(double a) - a redondeado, es un long
static int round(float a) - a redondeado, es un entero
Visto que hemos nombrado el paquete java.math, digamos que éste contiene dos clases, BigInteger e BigDecimal. La primera clase sirve para tratar números enteros de tamaño arbitrario, pongamos por ejemplo el cálculo factorial de un número muy grande, este será un número exageradamente grande. BigDecimal hace lo mismo con los números particulares.


Il package java.util


Antes de empezar esta lección tengo que hacer una pequeña advertencia.
Hemos visto como hay que programar usando Java, pero me he dado cuenta de que los teclados italianos no tienen tienen llaves, en cambio en los teclados que uso yo sí que aparecen. Por lo tanto os tengo que decir cómo podéis hacer aparecer estas llaves en vuestras pantallas.
Para que aparezca { hay que pulsar el teclado ALT, y manteniéndolo pulsado hay que teclear en el pequeño teclado numérico que está a la derecha el número 123 (ALT+123).
Para que aparezca } hay que teclear en cambio ALT+125.
Para los otros símbolos útiles en Java:
ALT Gr + es el de [ y ALT Gr + + de ]. Las teclas están subrayadas para no confundirlas con el signo + que indica che indica "pulsar a la vez". ALT Gr es el ALT que se encuentra a la derecha de la tecla ESPACIO, mientras que ALT se encuentra a la izquierda (mirando al teclado).

Este paquete es muy útil porque pone a disposición 34 clases y 13 interfaces que implementan algunas de las estructuras de datos más comunes. Algunas operaciones sobre fechas y sobre el calendario, y otras cosas.
Además el paquete java.util incluye otros subpaquetes que son: java.util.mime, java.util.zip y java.util.jar que sirven respectivamente para tratar archivos de tipo MIME, de tipo ZIP y de tipo Java Archive (JAR), que veremos en seguida en este capítulo. Como estructura de datos, en informatica, se llama a la estructura lógica lista para contenerun cierto número de datos en la que es posible insertar un datos, quitarlos, buscarlos, como mucho ordenarlos. Una simple estructura de daots que ya hemos visto es la array. Esta contiene un número cero de datos que pueden ser cualquier cosa, desde byte a objetos complejos, y sobre la misma se pueden incluir otros datos, hacer búsquedas o borrar, incluso un array se puede ordenar.
Para ve si en un array grande N está presente un dato X, yo tengo que visitar todo el array y hacer comparaciones con cada elemento del array, por lo que esta es una operación bastante compleja. Existen estructuras de datos que esta búsqueda la hacen empleando un solo acceso a la estructura, estas son, por ejemplo las citadas tablas hash. La elección de las estructuras de datos para usar en un programa es bastante complicada, por ello se elige una estructura en lugar de otra dependiendo del uso que se vaya hacer en el programa. Por ejemplo es difícil que en un database muy grande en el que se hacen muchas búsquedas se use un array como estructura de datos, porque empleareamos mucho tiempo para cada búsqueda (el ordenador es rápido, pero tiene sus límites si pensamos que éste emplea tanto tiempo para visitar completamente un database de mil millones de elementos), en este caso lo mejor tal vez sea emplear una tabla hash de cierta grandeza.
Java, por tanto, pone a disposción del usuario toda una gama de estructuras de datos, las gestiona, y a nosotros no nos queda más que usarlas. Para la elección de las estructuras de datos más acorde con nuestras intenciones, usaremos nuestro buen hacer porque, para elegirla de forma rigurosa son necesarios conocimientos específicos, entre otros los detalles que se realizan en las estructuras, estudiadas en cursos universitarios, como los algoritmos y Estructuras de Datos, y Fundamentos de Complejidad.
Cuando describa las clases de Java que se ocupan de la implementación de estas estructuras, las indicaré y trataré los tiempos de inserción, las búsquedas, etcétera…, pero siempre informalmente.
Vamos a ver qué incluye el paquete java.util

Interfaces

Collection
Comparator
Enumeration
EventListener
Iterator
List
ListIterator
Map
Map.Entry
Observer
Set
SortedMap
SortedSet

Estas interfaces establecen algunas propiedades de nuestras estructuras de datos. Se implementan en algunas de las siguientes clases.

Clases

AbstractCollection
AbstractList
AbstractMap
AbstractSequentialList
AbstractSet
ArrayList
Arrays
BitSet
Calendar
Collections
Date
Dictionary
EventObject
GregorianCalendar
HashMap
HashSet
Hashtable
LinkedList
ListResourceBundle
Locale
Observable
Properties
PropertyPermission
PropertyResourceBundle
Random
ResourceBundle
SimpleTimeZone
Stack
StringTokenizer
Timer
TimerTask
TimeZone
TreeMap
TreeSet
Vector
WeakHashMap

Excepciones

ConcurrentModificationException
EmptyStackException
MissingResourceException
NoSuchElementException
TooManyListenersException

Empezamos viendo algunas estructuras: BitSet, o en español Conjunto de Bit.
Esta clase ofrece una forma para crear y gestionar conjuntos bit (1,0) o mejor dicho, valores verdadero, falso.
El conjunto es desde luego un vector de bit pero que crece dinámicamente. Al principio los bit tienen un valor falso, y el vector mide 2^32-1 ((dos elevado a la treinta y dos) menos uno).
La clase tiene dos constructores: BitSet(), para crear un BitSet de dimensiones estándar, y BitSet(int nbits), para crear un BitSet que contiene nbits bit.
Las operaciones que se pueden hacer son:

void and(BitSet set), devuelve el and entre el BitSet y el otro BitSet localizados por set.
void andNot(BitSet set), borra todos los bit de la BitSet que tienen el correspondiente bit ajustado en la BitSet set.
void or(BitSet set), devuelve el or exclusivo entre el BitSet y el otro BitSet localizados por set.
void xor(BitSet set) , devuelve el or exclusivo entre el BitSet y el otro BitSet localizados por set.
void clear(int bitIndex), ajusta el bit especificado en falso.
void set(int bitIndex), ajusta el bit especificado en verdadero.
Object clone(), BitSet se declara Cloneable. Este método crea una copia igual.
boolean equals(Object obj), compara el objeto con otro objeto.
boolean get(int bitIndex), da el valor del bit número bitIndex.
int hashCode(), da un código hash para éste bitset.
int length(), da la grandeza lógica del bitset, es decir el bit más alto ajustado en verdadero más uno.
int size(), da el número de bit en el momento de la bitset. Es el bit más alto que se puede asignar a uno sin ampliar el bit set.
String toString(), transforma el bitset en una cadena

Probamos el bit set con el siguiente programa CaracteresUtilizados, que hay que editar en un archivo llamado CaracteresUtilizados.java, que coge una cadena en entrada y lee los caracteres que han sido utilizados.

import java.util.BitSet;
public class CaracteresUtilizados
{

public static void main (String[] a)
{

String tmp;

try {tmp=a[0];}
catch (ArrayIndexOutOfBoundsException e)
{errore();}

elabora(a[0]);

}

public static void error()
{

System.out.println("ERROR, necesito una cadena:");
System.out.println("tTeclear:");
System.out.println("ttjava CaracteresUtilizados CADENA.");
System.exit(0);

}

public static void elabora (String a)
{

String tmp = a;

BitSet utilizados= new BitSet();

for (ent e = 0; e < tmp.length() ; e++)
utilizados.set(tmp.charAt(i));

String out="[";

ent dim=utilizados.size();

for (ent e = 0; e < dim; e++)
{
if (utilizados.get(i))
out+=(char )i;
};

out+="]";

System.out.println(out);

System.out.println("Para redactar he utilizado un bit set de "+utilizados.size()+" bit");

System.out.println ("tttPietro ");

}

}

Analizamos otra clase di java.util, la clase Vector. Esta clase implementa unos array de Object. Lo interesante de los array del lenguaje, es que se puede modificar la largura del vector cuando se realiza la puesta en marcha.
En Vector, además de los constructores, tenemos tres tipos de métodos, los que sirven para modificar el vector, los que sirven para obtener los valores incluídos en el vector, y los que sirven para gestionar el crecimiento del vector.

Hay cuatro constructores:

Vector(), construye un vector de tamaño 10, y que tiene la posibilidad de aumento igual a cero.
Vector(Collection c), construye un vector que incluye los elementos de la colección especificada, en el mismo orden en el que aparecen en la colección.
Vector(int initialCapacity), construye un vector tan grande como initialCapacity, con posibilidad de aumento igual a cero.
Vector(int initialCapacity, int capacityIncrement), construye un vector grande initialCapacity, con la posibilida de aumento igual a capacityIncrement.

Algunos métodos de la clase son:

void add(int index, Object element), añade un elemento al vector en la posición indicada.
boolean add(Object o), añade un elemento al final del vector.
boolean addAll(Collection c), añade al final del vector los elementos de la colección especificada, en el mismo órden en el que aparecen en la colección.
boolean addAll(int index, Collection c), añade los elementos de la colección en el vector empezando por el código especificado.
Estos tres métodos se convierten en verdaderos si los elementos han sido añadididos.Se convierten en falsos si no tienen nada que ver.
void addElement(Object obj), añade el elemento al vector y aumenta la capacidad de uno. int capacity(), da la capacidad actual del vector.
void clear(), elimina todos los elementos que están en el vector.
Object clone(), método utilizado generalmente para clonar el objeto Vector, que es supuestamente cloneable.
boolean contains(Object elem), controla si el elemento especificado está en el vector.
boolean containsAll(Collection c), controla si toda la colección especificada está en el vector.
void copyInto(Object[] anArray), copia el contenido del objeto de tipo Vector en un array de objetos del lenguaje.
Object elementAt(int index), devuelve el elemento del vector que se encuentra en la misma posición especificada.
boolean equals(Object o), controla la identidad entre el vector y el objeto especificado.
Object firstElement(), da el primer elemento del vector en posición 0.
Object get(int index), da el elemento del vector que se encuentra en la posición especificada y lo borra del vector.
int hashCode(), da el código hash del vector.
int indexOf(Object elem), busca el primer dato elemento en el vector, y devuelve el índice. Con primer dato me refiero supuestamente al del índice más bajo.
int indexOf(Object elem, int index), busca el primer dato elemento en el vector empezando por el índice especificado y devuelve el índice.
void insertElementAt(Object obj, int index), incluye el objeto especificado en la posición que queramos del vector.
boolean isEmpty(), controla si el vector está vacío.
Object lastElement(), da el último componente del vector.
int lastIndexOf(Object elem), da el índice del último elemento del objeto especificado en el vector.
int lastIndexOf(Object elem, int index), como antes empezando por el índice especificado y moviéndose hacia detrás.
Object remove(int index), borra el elemento que se encuentra en la posición indicada en el vector.
boolean remove(Object o), borra el primer dato en el vector del objeto especificado.
boolean removeAll(Collection c), borra del vector todos los elementos incluidos en la colección especificada void removeAllElements(), borra todos los elementos del vector.
boolean removeElement(Object obj), borra el primer dato del objeto especificado en el vector.
void removeElementAt(int index), borra el elemento en la posición especificada.
boolean retainAll(Collection c), borra todos los elementos del vector que están incluidos en la colección especificada.
Object set(int index, Object element), sustituye los elementos en la posición especificada del vector con el elemento que se le da como parámetro (pone el element en la dirección index).
void setElementAt(Object obj, int index), pone el objeto especificado en la posición que queremos.
void setSize(int newSize), ajusta el nuevo tamaño del vector.
int size(), da el número de posiciones en el vector.
List subList(int fromIndex, int toIndex), crea un listado con los elementos del vector que se encuentran en la posición especificada come inicio o como final.
List es otra estructura de datos muy importante que Java lleva ya implementada.
Object[] toArray() e Object[] toArray(Object[] a), crean un array del lenguaje con los elementos incluidos en el vector.
toString(), da una representación bajo forma de cadena del vector que incluye las representaciones como cadena de todos los elementos incluidos en el vector. Prácticamente invoca el toString de todos los objetos.

Los que estén acostumbrados a programar con otros lenguajes de programación podrán apreciar la funcionalidad que a menudo el programador tiene que implementar él mismo de forma superficial. Lo que yo aprecio personalmente, como programador, es, además de la dinamicidad de la estructura de Vector, que siempre ha sido por definicón estática, la posibilidad de crear vectores con elementos heterogéneos. En realidad, éstos son vectores de objetos, y sabemos que los objetos de java pueden ser cualesquiera incluso programas. Por ejemplo, es posible crear un vector que incluya números enteros, valores booleanos y cadenas, lo que no se puede hacer con los demás array del lenguaje.
Para que quede más claro voy a poner un ejemplo.
Fijaos en este vector:

tribilín = { true , 10 , "Hola"};

¿De qué tipo será Tribilín? ent[]? boolean[]? O String[]? Ninguno de los tres. En Java es imposible crear un array hecho de esta forma, utilizando las famosas clases envoltorios, que, hasta ahora, nos habían parecido bastantes inútiles. Podemos crear un array y escribiremos.
Object[] tribilín={new Boolean(true),
new Integer(10),
new String("Hola")
};

Además, si utilizamos la clase Vector, tendremos muchos métodos para gestionar este vector de elementos heterogéneos.

Pongamos un pequeño ejemplo que usa los vectores. Definimos un espacio geométrico tridimensional de puntos, líneas y caras, que se definen así:

class punto
{
String nombre;
ent x,y,z;
public punto(String n, ent X,ent Y,ent Z)
{

x=X;

y=Y;

x=Z;

nombre=n;

}

public String toString()
{
return "n"+nombre+"="+x+","+y+","+z+"n";

}
}


class línea
{
String nombre;
punto inicio;
punto fin;
public línea(String n, punto i,punto f)
{

inicio=i;

fin=f;

nombre=n;

}

public String toString()
{
return "n"+nombre+"=("+inicio.toString()+","+fin.toString()+")n";

}

}


class cara
{
String nombre;
punto x1;
punto x2;
punto x3;
línea l1;
línea l2;
línea l3;
public cara(String n, punto X1,punto X2,punto X3)
{

x1=X1;
x2=X2;
x3=X3;
l1=new línea(n+"-línea1",x1,x2);
l2=new línea(n+"-línea2",x3,x2);
l3=new línea(n+"-línea3",x1,x3);
nome=n;

}

public String toString()
{

return "n"+nombre+"={"
+l1.toString()+
","
+l2.toString()+
","
+l3.toString()+"}n";

}
}

Las clases incluyen unos métodos toString(), que sobrescriben los métodos estándar para crear el outpu en el archivo del programa.
Las clases las pondremos en un archivo llamado Geometría.java, donde pondremos también los import necesarios al programa y las clases Geometría que incluye el main que definimos a continuación:
import java.util.*;
import java.io.*;

// Definicicón de la clase punto
// Definicicón de la clase línea
// Definicicón de la clase cara

public class Geometría
{

public static ent NÚMERO = 3000;

public static void main(String[] arg)
{
Vector espacio=new Vector(1,1);

System.out.println("Geometría en el espacio:");

ent pti = NÚMERO;

System.out.println();

System.out.println("Género "+pti+" objetos a caso por cada especie");

System.out.println("Cambiar la constante NÚMERO en Geometría para generar un número diferente.");

ent lin=NÚMERO;

ent car;

car=NÚMERO;


System.out.println();

ent d1=espscio.capacity();

System.out.println ("Capacidad del vector:"+espacio.capacity());

System.out.println("Redacto los puntos...");

ent e=0;

for ( e = 0 ; e {

float a=(float ) Math.random();

float b=(float ) Math.random();

float c=(float ) Math.random();

ent x=Math.round(a*1000);

ent y=Math.round(b*1000);

ent z=Math.round(c*1000);

String nome="Punto"+(e+1);

punto tmpP=new punto(nombre,x,y,z);

espacio.addElement(tmpP);

};

System.out.println ("Capacidad del vector:"+espacio.capacity());

ent d2=espacio.capacity();

System.out.println("Redacto las líneas...");

for ( e = 0 ; e {

float a=(float ) Math.random();

float b=(float ) Math.random();

float c=(float ) Math.random();

float d=(float ) Math.random();

float e=(float ) Math.random();

float f=(float ) Math.random();


ent x=Math.round(a*1000);

ent y=Math.round(b*1000);

ent z=Math.round(c*1000);

ent x1=Math.round(d*1000);

ent y1=Math.round(e*1000);

ent z1=Math.round(f*1000);

String nombre="Línea"+(i+1);

punto P1=new punto ("Punto 1 del "+nombre,x,y,z);

punto P2=new punto ("Punto 2 del "+nombre,x1,y1,z1);

linea tmpL=new linea(nombre,P1,P2);

espacio.addElement(tmpL);

};

System.out.println ("Capacidad del vector:"+espacio.capacity());

ent d3=espacio.capacity();

System.out.println("redacto las caras...");

for ( e = 0 ; e {

float a=(float ) Math.random();

float b=(float ) Math.random();

float c=(float ) Math.random();

float d=(float ) Math.random();

float e=(float ) Math.random();

float f=(float ) Math.random();

float g=(float ) Math.random();

float h=(float ) Math.random();

float j=(float ) Math.random();

ent x=Math.round(a*1000);

ent y=Math.round(b*1000);

ent z=Math.round(c*1000);

ent x1=Math.round(d*1000);

ent y1=Math.round(e*1000);

ent z1=Math.round(d*1000);

ent x2=Math.round(g*1000);

ent y2=Math.round(h*1000);

ent z2=Math.round(j*1000);

String nome="Cara"+(e+1);

punto P1=new punto ("Punto 1 del "+nombre,x,y,z);

punto P2=new punto ("Punto 2 del "+nombre,x1,y1,z1);

punto P3=new punto ("Punto 1 del "+nombre,x2,y2,z2);

cara tmpF=new cara(nombre,P1,P2,P3);

espacio.addElement(tmpF);

};

System.out.println ("Capacidad final del vector:"+espacio.capacity());

ent d4=espacio.capacity();

File FileOut=new File("Geometría.txt");

FileWriter Output;

try {Output=new FileWriter(FileOut);}
catch (IOException e) {Output=null;};

try {

Output.write("Geometría.txtnnúmero objetos="+3*NÚMERO+"n");

Output.write("Tamaño del Vector:al principio:"+d1+"n después de la inclusión de los números:"+d2);

Output.write("ndespués de la inclusión de las líneas:"+d3+"ndespués de la inclusión de las caras:"+d4);

Output.write("nnContenido:n");

Output.write(espacio.toString());

Output.write("nnnttPietro Castellucci");

Output.flush();

} catch (IOException e) {};

System.out.println("nLee el archivo Geometría.txt.n");

};

}

Si ponemos en marcha el programa veremos que el Vector espacio aumenta dinámicamente con los objetos heterogéneos punto, línea y cara.
Finalmente tendremos un archivo llamado Geometría.txt que incluye la descripción del vector. El archivo con 5 elementos por cada especie es algo como:

Geometría.txt
número objetos=15

Tamaño del Vector:

al principio:1
después de la inclusión de los puntos:5
después de la inclusión de las líneas:10
después de la inclusión de las caras:15

Contenido:
[
Punto1=653,932,0
,
Punto2=100,273,0
,
Punto3=855,210,0
,
Punto4=351,702,0
,
Punto5=188,996,0
,
Línea1=(
Punto 1 de la Línea1=680,454,0
,
Punto 2 de la Línea1=69,16,0
)
,
Línea2=(
Punto 1 de la Línea2=116,651,0
,
Punto 2 de la Línea2=371,15,0
)
,
Linea3=(
Punto 1 de la Línea3=947,335,0
,
Punto 2 de la Línea3=477,214,0
)
,
Línea4=(
Punto 1 de la Línea4=391,671,0
,
Punto 2 de la Línea4=692,725,0
)
,
Línea5=(
Punto 1 de la Línea5=762,283,0
,
Punto 2 de la Línea5=582,192,0
)
,
Cara1={
Cara1-línea1=(
Punto 1 de la Cara1=826,235,0
,
Punto 2 de la Cara1=13,378,0
)
,
Cara1-línea2=(
Punto 1 de la Cara1=12,950,0
,
Punto 2 de la Cara1=13,378,0
)
,
Cara1-línea3=(
Punto 1 de la Cara1=826,235,0
,
Punto 1 de la Cara1=12,950,0
)
}
,
Cara2={
Cara2-línea1=(
Punto 1 de la Cara2=382,30,0
,
Punto 2 de la Cara2=224,597,0
)
,
Cara2-línea2=(
Punto 1 de la Cara2=277,361,0
,
Punto 2 de la Cara2=224,597,0
)
,
Cara2-línea3=(
Punto 1 de la Cara2=382,30,0
,
Punto 1 de la Cara2=277,361,0
)
}
,
Cara3={
Cara3-línea1=(
Punto 1 de la Cara3=139,802,0
,
Punto 2 de la Cara3=880,935,0
)
,
Cara3-línea2=(
Punto 1 de la Cara3=643,921,0
,
Punto 2 de la Cara3=880,935,0
)
,
Cara3-línea3=(
Punto 1 de la Cara3=139,802,0
,
Punto 1 de la Cara3=643,921,0
)
}
,
Cara4={
Cara4-linea1=(
Punto 1 de la Cara4=516,614,0
,
Punto 2 de la Cara4=429,210,0
)
,
Cara4-línea2=(
Punto 1 de la Cara4=979,860,0
,
Punto 2 de la Cara4=429,210,0
)
,
Cara4-línea3=(
Punto 1 de la Cara4=516,614,0
,
Punto 1 de la Cara4=979,860,0
)
}
,
Cara5={
Cara5-línea1=(
Punto 1 de la Cara5=152,663,0
,
Punto 2 de la Cara5=828,101,0
)
,
Cara5-linea2=(
Punto 1 de la Cara5=651,761,0
,
Punto 2 de la Cara5=828,101,0
)
,
Cara5-línea3=(
Punto 1 de la Cara5=152,663,0
,
Punto 1 de la Cara5=651,761,0
)
}
]


Pietro Castellucci

Intentad fijar la constante NÚMERO a 4000 y poned en marcha el programa.
Como habéis visto hay muchas estrucuturas de datos en java.util, y describirlas todas sería demasiado trabajo.
Lo que nos interesa es que todas tienen métodos para introducir, quitar, recuperar y métodos para gestionar la estructura misma.
Las estructuras de datos implementadas son tablas hash, listas, pile, code, árboles etc… Según vuestras exigencias podeís utilizar una u otra. Para tener más detalles, sin embargo, os aconsejo ojear la documentación del Java Development Kit, donde stán escritas todas estas clases.
Por ahora os sirve con saber que las tablas hash son muy rápidas buscando un objeto. Por lo general, basta con un solo acceso a las estructuras de datos para encontrar el objeto que buscáis.
Los listados son como los vectores. Los objetos están relaccionados entre sí, y desde un obbjeto es posible alcanzar el siguiente o el anterior o los dos, según la realización del listado .
Los Pile son listados particulares, en los que se introducen objetos siempre al comienzo de la estructura y, de aquí, se pueden tomar. Por lo tanto en pila el último objeto que ha entrado es el primero que sale. Pensad en los objetos como si fueran unos documentos que hay despachar desde una oficina. Se ponen en órden en la mesa del encargado según sus llegadas, uno encima del otro. El encargado de despachar los documentos empieza siempre por el que está encima de la pila. Ésta puede parecer una estructura de datos tonta, pero os aseguro que es la más mportante de todas. Las utilizan todos los lenguajes de programación para invocar las funciones y los procedimientos. (Incluso Java la usa para invocar los métodos), para transladar los parámetros y recuperar los resultados. Sin esta estructura sería imposible programar de forma recursiva, que es una forma de programar muy potente.
Las colas funcionan al revés. Se pueden comparar con las colas de los bancos. Los objetos son las personas que están en la cola delante de la ventanilla. Llegan y se ponen al final de la cola. Mientras tanto el empleado atiende a las personas que están delante. Tambiém esta estructura es muy importante porque algunas variantes (las colas de prioridad, en las que los objetos tienen prioridad, se atienden según esta característica, es decir, se cuelan). Se utilizan mucho en los sistemas operativos como Windows, Linux, Unix, etc. para gestionar las necesidades de imprenta de una sola impresora por parte de todos los usuarios del sistema.
Antes de pasar al siguiente paquete, quiero mostraros una pequeña comparación sobre la búsqueda de un objeto entre muchos que están incluidos en distintas estructuras. Particularmente, en las estructuras de tipo vector y de tipo tabla hash.
Veremos como los resultados de la búsqueda cambian de forma evidente aumentando el tamaño de las estructuras. Imaginemos unos objetos de este tipo:

class O
{
String nombre=new String();
ent valor;
public O(String a, ent v)
{
nombre=a;
valor=v;
}
}

Creamos un vector de 100000 de estos elementos. Buscamos uno y vemos el tiempo que tardamos:

import java.util.*;

class O
{

String nombre=new String();

ent valor;

public O(String a, ent v)
{
nombre=a;
valor=v;
}

}



public class Rvector
{

public static ent NÚMERO = 100000;

public static void main (String[] s)
{

Vector V = new Vector(NUMERO);

ent numnombre=128756;

O O_30000=null;

System.out.println("Redacto el vector, introduzco "+NÚMERO+" objetos de tipo O con valores que no tienen relación con el índice.");

System.out.print("Inicio: O_"+numnombre);

for (ent e=0; i< NÚMERO;i++)
{

O tmp = new O("O_"+numnombre,numnombre);

if (numnombre==30000) O_30000 = tmp;

numnombre--;

V.add(e,tmp);

};
System.out.println(" Fin: O_"+numnombre);

System.out.println("Inicio la búsqueda de O_30000");

long Inicio=System.currentTimeMillis();

ent index=V.indexOf(O_30000);

O tmp=(O ) V.get(index);

long Fine=System.currentTimeMillis();

System.out.println("Oggetto O_30000 trovato in "+(Fin-Inicio)+" millisec. al índice "+index);

System.out.println("Vale:nNombre:"+tmp.nombre+"nValor:"+tmp.valor+"n");

}

}

El programa buscará el objeto O_30000. El output del programma es:
Redacto el vector, introduzco 100000 objetos de tipo O con valores independientes del índice.
Inicio: O_128756 Fin: O_28756
Empiezo la búsqueda de O_30000
Objeto O_30000 encontrado en 50 millisec. …..

Ahora hago lo mismo usando una estructura como la tabla hash:

import java.util.*;

class O
{

String nombre=new String();

ent valor;

public O(String a, ent v)
{
nombre=a;
valor=v;
}

}



public class Rhash
{

public static ent NÚMERO = 100000;

public static void main (String[] s)
{

Hashtable H = new Hashtable(NUMERO+1);

ent numnombre=128756;

O O_30000=null;

System.out.println("Redacto el cuadro, introduzco "+NÚMERO+" objetos de tipo O.");

System.out.print("Inicio: O_"+numnombre);

for (ent e=0; i< NÚMERO;e++)
{

O tmp = new O("O_"+numnombre,numnombre);

if (numnombre==30000) O_30000 = tmp;

numnombre--;

H.put(tmp,tmp);

};
System.out.println(" Fin O_"+numnombre);

System.out.println("Inicio la búsqueda de O_30000");

long Inizio=System.currentTimeMillis();

O tmp=(O ) H.get(O_30000);

long Fine=System.currentTimeMillis();

System.out.println("Obbjeto O_30000 encontrado en "+(Fin-Inicio)+" millisec. ");

System.out.println("Vale:nNombre:"+tmp.nombre+"nValor:"+tmp.valor+"n");


}

}

Otra vez el programa buscará el objeto O_30000. El output del programma es:
Redacto el vector, introduzco 100000 objetos de tipo O.
Inicio: O_128756 Fin: O_28756
Empiezo la búsqueda de O_30000
Objeto O_30000 encontrado en 0 millisec. …..

El paquete java.util no incluye sólo estas utilísimas estructuras de datos, sino también clases que simplifican la gestión de fechas y horarios, para la internacionalización, y otras clases de utilidad como el string tokenizer. Coge de una cadena todas las palabras y unos generadores de números casuales.



El paquete java.util


En esta lección veremos la parte de java.util que trata de los utilísimos archivos .zip e i .jar
Empezamos viendo java.util.zip
Los archivos .zip son archivos que contienen unos archivos comprimidos y varios programas. Se utilizan sobre todo para cambiar datos en internet porque reducen notablemente los tamaños.
Hay varios tipos de archivos comprimidos y varios programas para comprimir y ampliar los datos, pensemos en los archivos RAR, en los CAB de Windows, en los ARJ. Este paquete nos da la posibilidad de tratar datos comprimidos según los estándars ZIP y GZIP, que utilizan el algoritmo de compresión llamado DEFLATE. este paquete incluye también utility que controlan los códigos checksum CRC-32 y Adler-32 de un flujo arbitrario de entrada.
¿Para qué usar este paquete? Las razones son muchas. En primer lugar, los programas Java que incluyen imágenes, animaciones y sonidos, pueden ser realmente grandes y es posible crear un archivo .ZIP con todos los archivos necesarios para que funcione. De esta forma se disminuye el tamaño del mismo. Pero, para que se puedan utilizar por el programa, primero tienen que descomprimirse y este paquete nos ofrece esta posibilidad. Otra razón para usar este paquete es que la compresión de datos en informática es un problema bastante complejo. En esta operación se utilizan unos algoritmos que se basan en el álgebra de los números, tema no muy conocido fuera de las facultades de Ciencias. Por esta razón, son unos algoritmos bastantes incomprensibles para los que no tienen práctica en el asunto. Este paquete ofrece la posibilidad a todo el mundo de comprimir y ampliar estos datos.
Veamos, entonces, lo que incluye el paquete java.util.zip

Interfaces

Checksum, es un interfaz que representa el código checksum de los datos.

Clases

CheckedInputStream, es un flujo de entrada que trata también el checksum de los datos de entrada.
CheckedOutputStream, es un flujo de salida que trata también el checksum de los datos en salida.
CRC32, clase usada para calcular el código checksum de tipo CRC-32 de un flujo de datos.
Deflater, clase que se ocupa de las compresiones de los datos utilizando la compresión según la biblioteca
ZLIB.
DeflaterOutputStream, flujo de salida que comprime los datos utilizando el algoritmo Deflate.
GZIPInputStream, filtro para el stream de ingreso para leer datos comprimidos según el formato
GZIP.
GZIPOutputStream, filtro para el flujo de salida para escibir datos con el código zip utilizando GZIP.
Inflater, soporte para la compresión de tipo ZLIB.
InflaterInputStream, filtro para el flujo de entrada, para ampliar datos comprimidos según
el algoritmo Deflate.
ZipEntry, utilizada para representar un archivo de entrada de tipo ZIP.
ZipFile, utilizada para leer el contenido de un archivo ZIP.
ZipInputStream, utilizada para leer los archivos contenidos en un archivo ZIP.
ZipOutputStream, utilizada para escibir datos comprimidos de formato ZIP.

Excepciones

DataFormatException, error de formato de los datos.
ZipException

Cada una de estas clases tendrá sus métodos. Para conocerlos todos os remito a la documentación del JDK porque sólo analizaremos algunos con un pequeño ejemplo.
El siguiente programa abre el directorio en el que se encuentra y busca todos los archivos .zip, por cada archivo que encuentra y mira el contenido.

import java.util.*;
import java.util.zip.*;
import java.io.*;


public class ReadZip
{

public static void main(String [] a)
{
File dir=new File(".");

System.out.println("Abro el directorio "+dir.getAbsolutePath());

File[] cont=dir.listFiles();

ent MAX=cont.length;

for (ent e = 0; i {
String tmp=cont[i].getName();

if ((tmp.endsWith(".zip"))||(tmp.endsWith(".ZIP")))
{
// es un archivo .zip

System.out.println("He encontrado "+tmp);

controlaZip(cont[i]);

};
}


}

public static void controlaZip(File f)
{

System.out.println("Contenido del archivo "+f.getName());

ZipFile Zf;
try {Zf=new ZipFile(f);}
catch (ZipException e){Zf=null;}
catch (IOException e1){Zf=null;}
;

Enumeration files=Zf.entries();

while(files.hasMoreElements())
System.out.println(files.nextElement());


}


}

Además podemos ampliar estos archivos. El siguiente programa recoge todos los .zip del directorio donde se pone en marcha y los amplia.

import java.util.*;
import java.util.zip.*;
import java.io.*;


public class Decomp
{

public static void main(String [] a)
{
File dir=new File(".");

System.out.println("Abro el directorio "+dir.getAbsolutePath());

File[] cont=dir.listFiles();

ent MAX=cont.length;

for (ent e = 0; i<MAX; e++)
{
String tmp=cont[i].getName();

if ((tmp.endsWith(".zip"))||(tmp.endsWith(".ZIP")))
{
// es un archivo .zip

System.out.println("He encontrado "+tmp);

try {controlaZip(cont[i]);}
catch (IOException e){};

};
}


}

public static void controlaZip(File f) throws IOException
{

System.out.println("Ampliación del archivo "+f.getName()+":");

ZipFile Zf;
try {Zf=new ZipFile(f);}
catch (ZipException e){Zf=null;}
catch (IOException e1){Zf=null;}
;

Enumeration files=Zf.entries();

while(files.hasMoreElements())
{
ZipEntry tmpFile=(ZipEntry ) files.nextElement();

System.out.println("amplio el archivo "+tmpFile.getName());

System.out.println("tamaño comprimido "+
tmpFile.getCompressedSize()+" tamaño no comprimido "+
tmpFile.getSize()+" CRC "+tmpFile.getCrc());

System.out.println("modificado "+tmpFile.getTime());

InputStream in= Zf.getInputStream(tmpFile);

FileOutputStream out= new FileOutputStream(tmpFile.getName());


for (ent ch=in.read();ch!=-1;ch=in.read()) out.write(ch);


out.close();

in.close();

}

}


}

El paquete java.util.jar se pone a disposición del programador de las clases y de los interfaces para tratar los archivos de tipo Java Archive (JAR), sobre todo es posible leerlos y escribirlos. Los archivos JAR se basan en el estándar ZIP, con un archivo opcional llamado manifest .
El contenido del paquete es el siguiente:

Clases
Attributes
Attributes.Name
JarEntry
JarFile
JarInputStream
JarOutputStream
Manifest

Excepciones
JarException
Os remito a la documentación del JDK para más información.



El paquete java.net


 
El Paquete java.net

Java, como ya dijimos anteriormente, nació como lenguaje para la red y sólo sucesivamente se convirtió en un verdadero lenguaje de programación.
Su papel de líder para la programación no se pone en duda y, por eso, pone a disposición del programador diferentes paquetes para llevar a cabo esta programación.
Como el objetivo final del curso es programar Applet, tenemos que verlo aunque sea de modo superficial. El paquete es muy amplio y su contenido es el siguiente:

Interfaces
ContentHandlerFactory
FileNameMap
SocketImplFactory
SocketOptions
URLStreamHandlerFactory

Clases
Authenticator
ContentHandler
DatagramPacket
DatagramSocket
DatagramSocketImpl
HttpURLConnection
InetAddress
JarURLConnection
MulticastSocket
NetPermission
PasswordAuthentication
ServerSocket
Socket
SocketImpl
SocketPermission
URL
URLClassLoader
URLConnection
URLDecoder
URLEncoder
URLStreamHandler

Excepciones
BindException
ConnectException
MalformedURLException
NoRouteToHostException
ProtocolException
SocketException
UnknownHostException
UnknownServiceException

De todo esto nosotros veremos sólo algo. Para empezar vamos aver qué pasa en la red.
Los ordenadores en Internet comunican intercambiando paquetes de datos, llamados paquetes IP (Internet Protocol). Estos paquetes salen de un ordenador, pasan por varios nudos de la red (Servidor de la red) y llegan a su destino. Para establecer el recorrido intermedio entre los dos ordenadores que quieren comunicare se pone en marcha un algoritmo de routing (hay varios tipos según las exigencias y según el tipo de red).
Para establecer el remite de una comunicación, los destinatarios, los nudos internet, se necesita que cada ordenador conectado a la red tenga un nombre que lo identifique unívocamente. Este nombre es un número y se llama dirección IP.
La dirección IP es un número de 32 bit, que se puede escribir con varios formatos, sin embargo, el más utilizado es el formato decimal separado por puntos. Por ejemplo, una dirección IP es 594. 24.114.462 (Se ha elgido un número cualquiera).
Como los ordenadores recuerdan muy bien los números, pero nosotros los humanos no, se inventaron los DNS (Domain Name System) que asocian unos nombres a estas direcciones IP.
La primera clase del paquete que analizaremos es la InetAddres, que gestiona estas direcciones IP.
La clase tiene varios métodos, entre los que hay uno que devuelve las direcciones Ip del ordenador en el que se está trabajando, otro que, fijado un nombre de dominio, devuelve la dirección IP.
El siguiente ejemplo nos muestra el uso.

import java.net.*;
public class DireccionesIP
{
public static void main(String [] a)
{

String dom="developer.java.sun.com";

try {
InetAddress loc=InetAddress.getByName(dom);
System.out.println("IP de "+dom+" : "+loc.getHostAddress());
}
catch (UnknownHostException e)
{System.out.println("No existe el dominio "+dom);};


try {
InetAddress loc=InetAddress.getLocalHost();
System.out.println("IP local: "+loc.getHostAddress());
System.out.println("Nombre local"+loc.getHostName());
}
catch (UnknownHostException e)
{};

}

}

Como ejercicio, coged como nombre de dominio el primer tema del programa, por ejemplo,java DireccionesIP HTMLpoint

El paquete dota de clases útiles para tratar los socket fundamentales basados en TCP y en UDP, que son protocoles utilizados en la mayor parte de las aplicaciones Internet. Nosotros no los analizaremos, sino que pasaremos directamente a las clases que gestionan aplicaciones Web de nivel más alto.
Veamos la clase URL.
¿Qué es un URL? Un URL, o Uniform Resource Locator, es un puntero a un recurso web.
Un recurso web puede ser cualquier cosa, un directorio, un archivo, un objeto en red como, por ejemplo, una interfaz para hacer unas query a un database remoto, o para un motor de búsqueda.
Los URL son muchos, cada uno con un protocolo distinto, sin embargo los más utilizados son los que utilizan protocolos HTTP (HyperText Transfer Protocol) y FTP (File Transfer Protocol).
La clase URL se conecta con objetos web accediendo a éstos a través sus direcciones URL.
Vosotros que sois usuarios de HTMLpoint no necesitáis más explicaciones sobre el formato de las direcciones URL como http://www.cli.di.unipi.it/~castellu/index.html y que el index.html es opcional, es decir que la dirección URL http://www.cli.di.unipi.it/~castellu es igual a la anterior, que ~castellu es un directorio que se encuentra en el servidor, y que la dirección del servidor se identifica como http://www.cli.di.unipi.it . Sin embargo, os digo que, a diferencia de los web browser, l'http:// delante de la dirección es indispensable porque distingue el protocolo del URL, protocolo que el Navigator y el Explorer intuyen aunque se omitan. Cuando programemos los apliques utilizaremos sólo los URL para acceder también a los archivos locales, viéndolos como recursos de la red. Lo haremos porque en los apliques no se pueden utilizar los archivos, por razones de seguridad, entonces para leer un archivo hay que verlo como un recurso de la red.
Las últimas versiones de Java están eliminando esta limitación del lenguaje, utilizando unas firmas que permiten leer y escribir un archivo de forma controlada incluso en la red. Por eso en futuro será posible utilizar incluso los archivos en los archivos, siempre que se asuman algunas responsabilidades.
Veamos unos constructores de objetos URL:

URL(String spec) , crea un objeto URL según la representación a cadena, por ejemplo "HTMLpoint"
URL(String protocol, String host, int port, String file), crea un objeto URL, especificándolo todo, incluso la puerta.
URL(String protocol, String host, int port, String file, URLStreamHandler handler), como el anterior, lo único que especifica también la URLStreamHandler, que es la superclase común a todos los protocolos(HTTP,FTP,Gopher).
URL(String protocol, String host, String file), crea un objeto URL especificando el protocolo, el host y el Archivo en el servidor host, por ejemplo: URL("http","www.cli.di.unipi.it","~castellu/index.html").

Analizamos ahora unos métodos de la clase

boolean equals(Object obj), compara dos objetos URL.
Object getContent(), da el contenido del objeto URL.
String getFile(), da el nobre del archivo del URL.
String getHost(), el host
int getPort(), el número de la puerta
String getProtocol(), el nombre del protocolo.
String getRef(), da el puntero a la URL.
int hashCode(), da el código hash del objeto.
URLConnection openConnection(), abre una conexión con el objeto remoto indicado por la URL.
InputStream openStream(), abre una conexión con el objeto web indicado por la url en forma de flujo de lectura.
String toExternalForm(), da una cadena que representa la URL.
String toString(), da una representación del objeto URL.

A continuación damos un pequeño ejemplo de cómo se utiliza la clase URL.

import java.net.*;
import java.io.*;

public class getPage
{
public static void main(String[] arg)
{
String un;

try {un=arg[0];}
catch (ArrayIndexOutOfBoundsException e)
{
un="http://www.htmlpoint.com/index.asp";
System.out.println("Ninguna URL definida, cojo "+un);

};

System.out.println("URL:"+un);

URL url;

boolean tribilín=false;

try {url= new URL(un);}
catch (MalformedURLException e)
{
System.out.println("URL equivocado, cojo http://www.htmlpoint.com/index.asp ");

url = null;

tribilín=true;

};

if (tribilín) try {url = new URL ("http://www.htmlpoint.com/index.asp ");}
catch (MalformedURLException e){};

BufferedReader stream;
try {stream = new BufferedReader (new InputStreamReader (url.openStream()));}
catch (IOException e){
System.out.println("Error de apertura del archivo");
stream=null;
System.exit(0);
};

File out=new File("."+url.getFile());

FileWriter Output;

try {Output=new FileWriter(out);}
catch (IOException e) {Output=null;};

String l;
try
{

while ((l=stream.readLine())!=null)
{


Output.write(l);

};

Output.flush();

Output.close();

}
catch (IOException e){System.out.println("Error de lectura.");};
}

}

El programa coge una url de los parámetros de entrada; si éste no es válido o no hay parámetros, abre por default la url http://HTMLpoint/index.asp. Entonces recoge la página que ha leído y la guarda en el disco.
Como se puede ver, esto se parece a un web browser, utilizando un poco de gráfica se podría visualizar incluso la página. Intentad poner en marcha el programa poniendo las siguientes direcciones:

java getPage http://www.cli.di.unipi.it/~castellu/index.htm
java getPage http://www.cli.di.unipi.it/~castellu/pietro1.htm
java getPage http://www.cli.di.unipi.it/~castellu/quiénsoy.htm

y simplemente java getPage, y veréis los resultados.



Conclusiones sobre los paquetes



En este apartado hemos visto unos paquetes que contienen los API del lenguaje Java, pero hay más:

java.applet , que analizaremos en el próximo capítulo, sirve para crear unos programas que trabajan
en los web browsers, llamados applet.
java.awt , este paquete y sus subpaquetes implementan las clases para, a su vez, implementar los controles
GUI, para implementar interfaces gráficas, además de instrumentos para el dibujo, manipulación de las imágenes, imprimir y otras funciones. Lo veremos en el próximo capítulo
java.beans, paquete que permite definir los componentes Java y utilizarlos en otros programas.
java.rmi, paquete para la invocación de métodos remotos, es decir, de métodos de objetos que se encuentran en cualquier lugar en la red, para construir unas aplicaciones distribuidas.
java.security, hay clases que implementan las funciones de seguridad como, por ejemplo, las clases utilizadas para criptografar documentos antes de enviarlos a la red.
java.sql, interfaz entre el lenguaje Java y el lenguaje para base de datos SQL.
java.text, clases muy útiles para la interacción.
javax.accessibility, clases que apoyan las tecnologías que facilitan a los usuarios no aptos.
javax.swing, es una extensión de java.awt para construir apliques y aplicaciones gráficas: es prodigioso.
org.omg.CORBA, permite relacionar el lenguaje Java con el lenguaje CORBA.

Otra vez os animo, para saber más, a controlar la documentación del JDK, disponible On line, tanto para descargarla como para consultarla, en el sito de la Sun Microsystem www.sun.com .

Estos son los paquetes estándar del lenguaje Java. A estos se suman las extensiones estándar del lenguaje. Las extensiones estándar son paquetes que, en las próximas versiones de Java, se convertirán en paquetes estándar y que, hasta ahora, son versiones beta. Swing fue la extensión hasta que salió Java2. Ahora, de hecho, se utilizan más las viejas awt.

API Servlet, está destinada a la programación de aplicaciones del servidor en Java. API está formada por paquetes javax.servlet y javax.servlet.http.

Java 3D, gestiona el dibujo tridimensional y es parecida a la versión Java de OpenGL (JavaGL), la famosísima biblioteca de la SGI (alguien la conocen como Glide, es decir, como la biblioteca OpenGL por las 3Dfx) y DirectX de Microsoft.
Se puede bajar del sito: http://java.sun.com/products/java-media/3D/index.html

Java Media Framework, gestiona, en los programas Java, varios formatos audio, video y multimedial. Los archivos que los ayudan son los siguientes:
.mov, .avi, .viv, .au, .aiff, .wav, .midi, .rmf, .gsm, .mpg, .mp2, .rtp.
Si no toda, por lo menos una parte se convertirá en estándar con Java 1.3 que está a punto de salir al mercado (finales de abril). Se baja del sito:
http://www.javasoft.com/products/java-media/jfm/index.html

Speech, funciones de reconocimiento vocal, no sólo para las órdenes, sino que es posible también editar archivos enteros. Este paquete hace también el output vocal.
Se puede bajar del sito: http://java.sun.com/products/java-media/speech/index.html

Telephony, funciones de telefonía y fax.

JavaMail, clases para gestionar el correo electrónico.

Java Naming and Directory Services, para acceder a los servicios de nombres y directorio utilizando protocoles como LDAP.
este paquete se ha convertido en estándar en JDK 1.3

Java Management, para la gestión de redes locales.

JavaSpaces, más clases para la creacción de aplicaciones distribuidas.

JavaCommerce, para el comercio electrónico.

Personalmente no veo la hora de que se conviertan en estándar las API Java 3D, Java Media Framework, JavaSpeech y Java Telephony, porque las funciones que prometen estas API son realmente excepcionales. Utilizarlas ahora es posible, pero con cierto riesgo. Realmente son todavía versiones beta y, por eso, llenas de errores. Además si se quieren escribir apliques utilizando estas nuevas funciones, esto es posible, pero para ponerlos en marcha se necesita el apliqueviewer del JDK, porque seguramente el Java implementado en los web browser todavía no las tiene. Hay que pensar que Swing se ha convertido en un paquete estándar del lenguaje, pero existen todavía unos browser que no lo tienen.




Interfaces gráficas y sucesos


 
Por fin llegamos a la programación de interfaces gráficas, es decir, a la creacción de apliques y de aplicaciones a ventanas. En primer lugar, intentamos establecer qué es un interfaz y qué quiere decir hacerla gráfica.
Cada programa, como ya dijimos, se puede ver como un objeto que calcula una función, es decir, que coge unos datos del exterior y devuelve unos resultados. Por ejemplo, pensemos en un simple programa que calcula la suma de dos números. Este programa cogerá como input dos números y devolverá como output un solo número que representa la suma de los primeros dos.
Lo que acabamos de decir es válido en general para todas las aplicaciones y no es un caso específico del ejemplo anterior. Pensemos en un videojuego: el input lo dará la palanca de control, y el output sará la gráfica que aparece en la pantalla. Por esta razón, conceptualmente tanto el videojuego como el programa suma, como cualquier programa que un programador pueda inventarse, son funciones calculadas sobre unos datos de entrada que devuelven resultados.
La interfaz del programa hacia el usuario que la utiliza es la manera en que el programa coge los datos del usuario y le devuelve los resultados.

Hasta ahora vimos unas interfaces de texto, el caso de la suma de los números en las que los datos se cogían del input estándar con una System.in.read() y los resultados se imprimían en el output estándar con una System.out.print().
Las System.in y out representan una interfaz del programa hacia el exterior, en este caso, hacia el usuario.
Otras interfeces con el exterior que ya hemos analizado, son los archivos que representan interfeces de entrada o de salida hacia usuarios u otros programas.
Estableciendo una pequeña comparación, no tan imposible, entre un programa y el hombre, podemos decir que la interfaz en entrada del cerebro está representada por la vista, el tacto, el gusto, el oído y el olfato, mientras la interfaz de salida está representada por la palabra y el movimiento de los músculos.
Notar que esto no es algo muy raro porque los robots, aunque no tienen los mismos canales de entrada que los hombres (tienen la vista, una especie de tacto, algo que indica la proximidad) y de salida (a menudo hablan, en lugar de los músculos tienen motores eléctricos conectados a brazos mecánicos, pinzas, etc...), tienen el mismo funcionamiento del hombre. Realizan acciones (dan un ouput) consecuentemente a unos estímulos (señas de input), aunque por supuesto el hombre es mucho más complejo gracias a su capacidad de pensamiento que todavía la inteligencia artificial no consigue alcanzar totalmente. Realmente un robot no puede decidir nada al conocer sólo informaciones parciales sobre un problema, en cambio el hombre puede hacerlo porque es capaz de formular hipótesis, etc.…).

Por tanto, la interfaz está compuesta por todos los canales de los que un programa recoge informaciones y hacia las que devuelve unos resultados.
Algunos datos de entrada sirven para que cambie sólo el estado del programa, otros, en cambio, dan inmediatamente un output. Nosotros los consideramos todos datos en los que se calculan funciones. Realmente una función se calcula también teniendo en cuenta el estado del programa y, también, el estado y, por consiguiente, el input que le ha cusado es un input de la función.
Aclaro este tema con un ejemplo. Pensemos en un programa que calcula dos funciones, una de suma y otra de sustracción entre dos números, y pensemos en un input que toma un número para elegir un estado (1 o 2), y después dos números. A estos dos números se les aplica la función suma o la función sustracción según el estado del programa.

Poe ejemplo:

INPUT: <1,10,10> à OUTPUT: 20
INPUT:<2,10,10> à OUTPUT: 0

En el ejemplo, el input sobre el estado se usa para calcular el output.

Lo que nos interesa es la interfaz del usuario. Vimos como los programas pueden relaccionarse con otros programas o con periféricas (enviando, por ejemplo, órdenes a una impresora), pero esto no nos interesa. Nos interesa en cambio ver todo lo que le sirve al programa para dialogar con el usuario, es decir, la llamada interfaz del usuario.
En este caso nos interesa ver la interfaz gráfica del programa, es decir, la interfaz que hace mucho más agradable el programa al usuario, en lugar de la gris interfaz de caracteres que vimos antes.
La interfaz gráfica del programa está compuesta por los llamados componentes GUI (Graphics User Interface), que son componentes que sirven para el input o el output y tienen un aspecto gráfico. Son, por ejemplo, unos componentes GUI de un programa, todos los menús, los pulsadores, las etiquetas, etc….
Todas estas GUI estrán, obviamente, conectadas a una estructura que las incluye. Las dos estructuras que analizaremos, ya que son las más importantes, son los apliques y las ventanas.

Cada GUI es, entonces, un trocito de interfaz gráfica, reciben los sucesos y, de acuerdo con éstos, dan unos resultados. Pensemos en un pulsador: se puede clicar o dejar de clicar. Cuando un usuario programa una interfaz gráfica que incluye un pulsador tendrá que gestionar incluso los sucesos asociados a éste, es decir, tendrá que decir qué ocurre cuando se clica el pulsador, cuando se deja de clicar, cuando le pasamos el ratón encima, etc.
Cada GUI tendrá un tipo de suceso asociado, algunos los gestionan automáticamente las clases que se amplian para incluir el GUI en la ventana (por ejemplo, la modificación gráfica del pulsador clicado que se pone en evidencia); otros los puede definir el usuario (como el clic de un pulsador, si no hay gestor no ocurre nada) y otros los tiene que definir el usuario (como todos los sucesos del teclado cuando queremos escuchar por lo menos uno de éstos, por ejemplo, nos interesa programar cómo se pulsa una tecla, tenemos que gestionar incluso la presión, etc.…).
Cada tipo de suceso, para cada tipo de componente GUI, tiene que ser declarado como escucha del suceso. Es un programa que espera que el suceso ocurra sobre el componente y cuando esto ocurre, lo gestiona.
La programación de interfaces gráficas es, por esta razón, diferente de la normal programación porque se dibujan las interfaces y luego se gestionan los suceos que llegan, mientras que en las normales aplicaciones había un main que representaba todo el programa. La gestión de los sucesos en Java ha cambiado de la versión 1 a Java 2 (JDK 1.2 para arriba). Nosostros analizaremos la nueva gestión de los sucesos, la de Java 2 porque la primera fue cambiada porque no se entendía a que componente se asocia el suceso.

En nuestra explicación de los componentes GUI analizaremos cómo definirlos, cómo inicializarlos, cómo introducirlos en una ventana o en un aplique y, finalmente, cómo gestionar los sucesos.
Como ya dijimos, Java 2 tiene dos colecciones de paquetes para las interfaces gráficas, java.awt, que ya existía en Java 1, y javax.swing, que salió con Java 2, construida sobre las AWT, que aumenta muchísimo las posibilidades para las interfaces gráficas.




¿Qué es una aplicación a ventanas?


 
La aplicación a ventanas es el tipo de aplicación que más a menudo utilizamos cuando trabajamos con el ordenador. Es una aplicación que se pone en marcha de forma local, que utiliza como interfaz del usuario las tecnologías de las ventanas típica de los sistemas operativos Mac OS (en la que nació), Windows (todas sus variantes, Windows 3.1, Windows 95, 95-OSR2, 98, NT, 2000 y Millenium), XWindows (el servidor gráfico para Linux y Unix).
Casi todos los programas que se utilizan actualmente son aplicaciones a ventanas. Lo son, por ejemplo, Word, Netscape, Explorer, Jbuilder, Visual Studio, WinZip, Paint, XV, etc… (Todos pertenecen a los correspondientes productores).
Por lo tanto veremos cómo se crea una Ventana usando el paquete AWT.
Como siempre creamos una aplicación con el main, como hicimos anteriormente. Sin embargo, la clase que creamos ahora ampliará la clase java.awt.Frame, que representa la ventana completa, incluye el título, los pulsantes de reducción a icono, maximizar y cerrar.
La clase Frame tiene varios métodos y constructores que veremos dentro de poco. Ahora vamos a crear nuestra primera ventana con el título Primera Ventana y que no incluye nada. La editamos en Ventana.java.

import java.awt.*;

public class Ventana extends Frame
{

public Ventana()
{

super("Primera Ventana");

setLocation(100,100);

setSize(200,100);

show();

}



public static void main(String[] arg)
{
new Ventana();

System.out.println("he creado la ventana");
}

}

Al principio, como para cada aplicación, se invoca el main que crea un nuevo objeto de tipo Ventana. (El main y la ventana podrían estar en dos archivos separados, uno que gestiona el main, y el otro que gestiona la ventana).
En el constructor del objeto ventana se invoca al constructor de la superclase, es decir, del frame, con la cadena "Primera Ventana" (es el título). Luego se invoca el método setLocation que declara la posición del ángulo derecho en la parte que está arriba de la ventana en el desktop, en este caso <100, 100> (Son la x y la y respectivamente. La x se mide partiendo del lado izquierdo de la pantalla y aumenta a medida que se va hacia la derecha. La y se mide partiendo de la parte superior de la pantalla y aumenta a medida que se va hacia abajo).
Después se invoca el método setSize que permite especificar anchura y altura. En nuestro caso, tiene una anchura de 200 y una altura de 100. Finalmente se invoca el método show() y a continuación aparece la ventana en la pantalla.




Las coordinadas de la pantalla no son las coorinadas cartesianas. realmente la y es precisamente opuesta porque aumenta a medida de que se baja y desminuye a medida de que se sube. Éste es un problema que tiene no sólo Java, sino que todos los lenguajes de programación y todas las bibliotecas para la gráfica Raster. Se debe a razones históricas, supongo, debidas a la forma de dibujar los pixel en pantalla a nivel de hardware. Hay que acostumbrarse, pero las primeras veces puede provocar problemas de razonamiento.
Intentad redactar y poner en marcha el programa y cuando veáis vuestra primera ventana os animaréis. Sucesivamente eliminad, por turnos, los métodos setLocation, setSize y show, colocad también las ventanas en distintas posiciones y evaluad los cambios. En el ejemplo, se ven sucesos que el sistema gestiona automáticamente. Son Ir Resize de la Ventana y la presión de los pulsadores reduce a iconos y maximiza (minimiza), los cuales se gestionan en la clase Frame.
En cambio, no se gestiona el suceso cerrar ventana (el pulsador de la x). Si se teclea no ocurre nada y para acabar la puesta en marcha del programa hay que ir al prompt del DOS desde el que empezó la aplicación y teclear CTRL+C (el exit para todos los programas DOS).
Por último, creo que queda claro, la aplicación no funciona en ambientes que no son gráficos, es decir, en DOS y en Linux. Se necesita Windows (y el DOS cargado en una ventana, es decir, prompt de MS-DOS) o Xwindows con una shell abierta.

Además no es verdad que a una aplicación se puede asociar a una solo ventana. Java es un lenguaje que permite la multiprogramación. Cada ventana es un programa independiente que trabaja contemporaneamente con otros. Por eso puedo crear, para la misma aplicación, más ventanas FRame, como en el ejemplo que ofrecemos a continuación.

import java.awt.*;

public class Ventanas extends Frame
{

public Ventanas(String Nombre, ent x, ent y)
{

super(Nombre);

setLocation(x,y);

setSize(200,100);

show();

}



public static void main(String[] arg)
{

System.out.println("Creo 4 ventanas solapadas");

for (ent e1;i<5;i++) new Ventanas("Ventana "e,10+(e*10), 10+(e*10));

System.out.println("Creo 4 ventanas a cuadros");

for (ent e=5;e<9;e++) new Ventanas("Ventana "+e,(e-5)*200, 100+(e-5));


System.out.println("He creado las ocho ventanas");
}

}

Las mismas cosas se podían hacer extendiendo la clase JFrame del paquete javax.swing.

import javax.swing.*;

public class VentanaSwing extends JFrame
{

public VentanaSwing()
{

super("Primera Ventana");

setLocation(100,100);

setSize(200,100);

show();

}



public static void main(String[] arg)
{
new VentanaSwing();

System.out.println("He creado la ventana");

}

}

Este programa es como Ventana.java. lo único que amplía JFrame de swing. Las únicas diferencias son el contenido de la ventana, que esta vez es gris y antes era blanco, y el pulsador cerrar, que esta vez cierra la ventana (sólo la ventana y no toda la aplicación). Realmente la utilización de swing y de awt es muy parecida. Sin embargo, swing es más complejo y pone a disposición muchas más clases, y ofrece la posibilidad de cambiar el aspecto de las ventanas a runtime, etc.
Desgraciadamente, no todos los web browser las pueden utilizar. Por eso, nosotros veremos las awt, y después hablaremos de las swing, dejando claro que los que quieran hacer un aplique para su propria página html hasta ahora TIENEN que utilizar las awt. Dentro de poco, cuando el XML se convierta en estándar y se tengan que cambiar los browser, se podrá utilizar con toda tranquilidad swing incluso para los apliques.
Por lo tanto, vemos qué incluye la clase Frame. En primer lugar, los constructores son dos:

Frame() , que crea un Frame sin ningún título, al principio invisible.
Frame(String T), que crea un Frame con título T, también inicialmente invisible.

Los atributos de la clase son:
static int ICONIFIED
static int NORMAL

para indicar el estado de las ventanas y

static int CROSSHAIR_CURSOR
static int DEFAULT_CURSOR
static int E_RESIZE_CURSOR
static int HAND_CURSOR
static int MOVE_CURSOR
static int N_RESIZE_CURSOR
static int NE_RESIZE_CURSOR
static int NW_RESIZE_CURSOR
static int S_RESIZE_CURSOR
static int SE_RESIZE_CURSOR
static int SW_RESIZE_CURSOR
static int TEXT_CURSOR
static int W_RESIZE_CURSOR
static int WAIT_CURSOR

Todos se declaran como deprecated, para los cursores, remplazados por la clase Cursor. Hereda la alineación de los componentes de Component.

Los métodos son:

void addNotify(), conecta el frame a un recurso de la pantalla y lo convierte en visible.
int getCursorType(), declarado Deprecated. Es de la versión 1.1 de las JDK
static Frame[] getFrames(), da un array que incluye todos los Frames creados por la aplicación.
Image getIconImage(), da el icono del Frame. Es un objeto de tipo Icon, que analizaremos a continuación.
MenuBar getMenuBar(), devuelve la barra de los menús del frame. Es un objeto de tipo MenuBar, que analizaremos a continuación.
int getState(), da el estado del frame.
String getTitle(), da el título del frame
boolean isResizable(), da verdadero si el frame se puede agrandar y reducir con el ratón.
protected String paramString() , da la cadena que incluye los parámetros del Frame.
void remove(MenuComponent m), quita el MenuBar especificado por el frame.
void removeNotify(), quita la conexión entre el frame y el recurso que representa la pantalla, convirtiéndolo en algo que no se puede visualizar.
void setCursor(int cursorType), controla el cursor en JDK1.1. Se declara deprecated.
void setIconImage(Image image), averigua el icono del Frame.
void setMenuBar(MenuBar mb), asigna una MenuBar al frame.
void setResizable(boolean resizable), averigua el Frame que puede cambiar dimensiones o no. Por default lo es.
void setState(int state), averigua el estado del frame
void setTitle(String title), averigua el título del frame.

Frame es una clase que amplía java.awt.Window y, por eso, hereda los métodos y los atributos.
Realmente Frame es una Window que añade un borde y un MenuBar. Los métodos heredados de windows son:

addWindowListener, applyResourceBundle, applyResourceBundle, dispose, getFocusOwner, getInputContext, getLocale, getOwnedWindows, getOwner, getToolkit, getWarningString, isShowing, pack, postEvent, processEvent, processWindowEvent, removeWindowListener, show, toBack, toFront.

Window amplía java.awt.Container, es un contenedor de objetos AWT. Es un componente que puede incluir otros componentes. Por lo tanto, por la propiedad de la transitividad, Frame hereda los métodos y los atributos. Los métodos son:

add, add, add, add, add, addContainerListener, addImpl, countComponents, deliverEvent, doLayout, findComponentAt, findComponentAt, getAlignmentX, getAlignmentY, getComponent, getComponentAt, getComponentAt, getComponentCount, getComponents, getInsets, getLayout, getMaximumSize, getMinimumSize, getPreferredSize, insets, invalidate, isAncestorOf, layout, list, list, locate, minimumSize, paint, paintComponents, preferredSize, print, printComponents, processContainerEvent, remove, remove, removeAll, removeContainerListener, setFont, setLayout, update, validate, validateTree

Container amplía java.awt.Component. Un Component es un objeto que tiene una representación gráfica, por ejemplo un cursor será una extensión de esta clase que amplía, a su vez, java.lang.Object
Los atributos heredados por Component son:

BOTTOM_ALIGNMENT, CENTER_ALIGNMENT, LEFT_ALIGNMENT, RIGHT_ALIGNMENT, TOP_ALIGNMENT

mientras los métodos heredados por Component son:

action, add, addComponentListener, addFocusListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addPropertyChangeListener, addPropertyChangeListener, bounds, checkImage, checkImage, coalesceEvents, contains, contains, createImage, createImage, disable, disableEvents, dispatchEvent, enable, enable, enableEvents, enableInputMethods, firePropertyChange, getBackground, getBounds, getBounds, getColorModel, getComponentOrientation, getCursor, getDropTarget, getFont, getFontMetrics, getForeground, getGraphics, getHeight, getInputMethodRequests, getLocation, getLocation, getLocationOnScreen, getName, getParent, getPeer, getSize, getSize, getTreeLock, getWidth, getX, getY, gotFocus, handleEvent, hasFocus, hide, imageUpdate, inside, isDisplayable, isDoubleBuffered, isEnabled, isFocusTraversable, isLightweight, isOpaque, isValid, isVisible, keyDown, keyUp, list, list, list, location, lostFocus, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paintAll, prepareImage, prepareImage, printAll, processComponentEvent, processFocusEvent, processInputMethodEvent, processKeyEvent, processMouseEvent, processMouseMotionEvent, removeComponentListener, removeFocusListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, repaint, requestFocus, reshape, resize, resize, setBackground, setBounds, setBounds, setComponentOrientation, setCursor, setDropTarget, setEnabled, setForeground, setLocale, setLocation, setLocation, setName, setSize, setSize, setVisible, show, size, toString, transferFocus

Mientras que de Object se heredan los mismos métodos:

clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

Algunos los analizaremos, mientras que para los demás os aconsejo consultar la documentación del JDK, en la que están descritas todas detalladamente.

El diagrama de las extensiones de Frame es el siguiente:



Llegados a este punto, se entiende por qué es importante la extensión de las clases en Java. Realmente en Frame se pueden invocar todos los métodos que analizamos antes.

En cambio, el método de JFrame de swing es:



Por lo tanto Jframe hereda todos lo métodos de Frame porque deriva de éste y, además, crea otros.




¿Qué es un aplique?


 
Un aplique no es más que una aplicación Java que se encuentra en web. El aplique presenta unas diferencias con las aplicaciones porque no tienen ningún main, y son clases que tienen el mismo nombre que el del archivo que las incluye, que amplían la clase Applet del paquete java.applet.
Incluso para los apliques existe la versión JApplet de swing, que se utiliza para introducir componentes Swing en lugar de componentes AWT. Un aplique necesita un archivo html que lo invoque. Por ejemplo, PrimoApplet.java, el aplique que queremos poner en marcha, lo redactamos y el compilador genera PrimoApplet.class. Para ponerlo en marcha necesitamos un archivo html que incluya el TAG en su interior:

<applet code="PrimoApplet.class" ></applet>

Si este archivo se llama tribilín.html, llegados a este punto tenemos dos posibilidades para poner en marcha el aplique. La primera, en fase debug, es utilizar el programa appletviewer de JDK y, para esto, tendremos que escribir partiendo del prompt de dos:

appletviewer tribilín.html

La segunda es utilizar un web browser, como Explorer o Netscape invocando el archivo tribilín.html.
Como se puede ver, se pone en marcha siempre el archivo html, y no el archivo .class como ocurría para las aplicaciones. Es el archivo html el que invoca la aplicación .java.
Para más informaciones sobre las páginas html os aconsejo visitar el sito HTMLpoint donde se encuentran apartados que tratan este tema. Nosostros prepararemos unas páginas sencillas que sirven sólo para cargar nuestros apliques. por ejemplo, para el aplique PrimoApplet.class de antes, el archivo tribilín.html será algo parecido a:

<html>
<head>
<title>Applet PrimoApplet
</head>
<body>

El siguiente es el aplique PrimoApplet.class

<applet code="PrimoApplet.class" width=100 height=100>¡Tu browser es viejo, tienes que cambiarlo!</APPLET>
</body>
</html>

Hasta ahora hemos visto cómo poner en marcha el aplique, ahora lo tenemos que crear. En primer lugar tenemos que crear una clase llamada PrimoApplet, que amplía la clase java.applet.Applet, y tenemos que definir unos métodos que el sistema (appletviewer o el browser) invocará automáticamente. Uno de estos métodos se llama paint(Graphics O), y Graphics es un objeto que representa la pantalla del aplique. Nosostros lo volveremos a definir de forma que salga en pantalla lo que queramos.
Utilizaremos el método drawString de la clase Graphics para imprimir una cadena en la pantalla.
El programa PrimoApplet.java es

import java.applet.*;
import java.awt.*;

public class PrimoApplet extends Applet
{

public void paint (Graphics g)
{
g.drawString("Hola, yo soy el primer aplique.",0,50);
}

}

El paquete aplique contiene tres interfaces y una clase:
Interfaces

AppletContext, esta interfaz corresponde al ambiente del aplique, es decir al documento que lo incluye y a los demás apliques que están el en mismo documento.
AppletStub, se refiere al ambiente de puesta en marcha del aplique, tanto el browser como el appletviewer. AudioClip, la interfaz es una simple abstracción para que toquen unos audios.

Clase
Aplique

Analizamos la clase Applet más detalladamente.
El constructor es único, sin argumentos.
Aplique()

Hay unos métodos invocados del browser o de appletviewer automáticamente, que son: void init(), este método se invoca nada más cargar completamente en el sistema el aplique.
Se utiliza principalmente para inicializar el aplique.

void start(), invocado cuando el sistema pone en marcha el aplique y le avisa del suceso.
void stop(), invocado cuando el sistema bloquea la puesta en marcha del aplique y le avisa del suceso, invocado cuando se teclea STOP del appletviewer y cambia la página en el browser.
void destroy(), invocado cuando el aplique se destruye, es decir, cuando cambiamos, sale del browser o del appletviewer

Por lo tanto el ciclo vital de un aplique es:

Se carga y, sucesivamente, se le da el nombre de init();
Se pone en marcha, se teclea start(). Invoca el método paint() de la superclase Container;
Se para tecleando stop del browser o, cuando la ventana que lo incluye no está en primer plano, se teclea stop(). Cuando vuelve en primer plano se teclea start();
Finalmente, se destruye cuando se sale del browser que lo puso en marcha. En primer lugar se invoca stop y, sucesivamente, el destroy();
En el ejemplo que ponemos a continuación, se visualizan las fases precedentes para ver los resultados con un browser, visto que el output son System.out.print(). Seleccionar en herramientas (tool), show java consola (o parecidos), con el appletviewer, en cambio, el output se escribe en la ventana de la que se invoca el html que invoca el aplique.
Lo editamos en el archivo Etapas.java:

import java.applet.*;
public class Etapas extends Applet
{
public Etapás()
{

System.out.println("Invocado el constructor de Etapas");

}
public void init()
{

super.init();

System.out.println("Puesto en marcha public void init()");

}
public void start()
{

super.start();

System.out.println("Puesto en marcha public void start()");

}
public void stop()
{

super.stop();

System.out.println("Puesto en marcha public void stop()");

}
public void destroy()
{

super.destroy();

System.out.println("Puesto en marcha public void destroy()");

}
}

Lo redactamos con: javac Etapas.java
Para cargarlo vamos a crear el archivo Etapas.html que incluye:

<html>
<head>
<title>Etapas.html carga Etapas.class</title>
</head>
<body>
El siguiente es el aplique Etapas, que nos muestra las etapas por las que pasa el aplique.
<BR>
<applet code="Etapas.class" width=200 height=100>¡Tu browser es viejo, tienes que cambiarlo!</APPLET>
</body>
</html>

Pra ponerlo en marcha teclearemos: appleviewer Etapas.html, o abriremos el archivo Etapas.html con nuestro browser preferido.

Los demás métodos de la clase Applet son:

AppletContext getAppletContext(), da el AppletContext asociado al aplique, es decir, el documento que lo puso en marcha y los demás invocados por éste.
String getAppletInfo(), da informaciones sobre el aplique, tiene que ser sobrescrita, la normal da nulo.
AudioClip getAudioClip(URL url), da el objeto de tipo AudioClip asociado al URL introducido. Os recuerdo que la URL es un recuso del web.
AudioClip getAudioClip(URL url, String name), da el objeto de tipo AudioClip asociado a la URL y al nombre .
URL getCodeBase(), da la url asociado al aplique.
URL getDocumentBase(), da la url del documento html que ha invocado el aplique.
Image getImage(URL url), da el objeto de tipo Image asociada a la url introducida y se puede imprimir en la pantalla.
Image getImage(URL url, String name), da el objeto de tipo Image asociado a la url y al nombre.
Locale getLocale(), da el objeto de tipo Local asociado al aplique y se ocupa de la internacionalización. Se encuentra en el paquete java.util.
String getParameter(String name), da el valor del parámetro llamado name tomado de la página html que invoca el aplique. El aplique, por lo tanto, se puede invocar con valores de entrada, como el args del main. Este método los recoge.

Por ejemplo, si invoco el aplique Clock.class de esta forma:

<applet code="Clock" width=50 height=50>
<param name=Color value="blue">
</applet>

Si en código del aplique escribo getParameter("Color") el resultado será "blue".
String[][] getParameterInfo(), da un array que incluye informaciones sobre los parámetros del aplique. boolean isActive(), nos dice si el aplique está activo.
static AudioClip newAudioClip(URL url), coge un AudioClip de un dato url.
void play(URL url), toca el audio clip tomado de la url absoluto.
void play(URL url, String name), toca el Clip que nos da la url y el nobmre especificado.
void resize(Dimension d) o void resize(int width, int height), pide al plique que modifique sus dimensiones. Dimension es un objeto awt que es una dimensión, es decir, un valor de anchura y altura.
void setStub(AppletStub stub), ajusta el AppletStub del aplique al nuevo stub.
void showStatus(String msg), pide al aplique que la cadena se imprima en la ventana de estado del aplique.

Un aplique es una extensión de Panel, que es un simple contenedor. De éste hereda el método: addNotify

Panel amplía Container del que hereda y hace heredar a Applet, los métodos: add, add, add, add, add, addContainerListener, addImpl, countComponents, deliverEvent, doLayout, findComponentAt, findComponentAt, getAlignmentX, getAlignmentY, getComponent, getComponentAt, getComponentAt, getComponentCount, getComponents, getInsets, getLayout, getMaximumSize, getMinimumSize, getPreferredSize, insets, invalidate, isAncestorOf, layout, list, list, locate, minimumSize, paint, paintComponents, paramString, preferredSize, print, printComponents, processContainerEvent, processEvent, remove, remove, removeAll, removeContainerListener, removeNotify, setFont, setLayout, update, validate, validateTree

A su vez Container amplía Component, y, por lo tanto, están los atributos

BOTTOM_ALIGNMENT, CENTER_ALIGNMENT, LEFT_ALIGNMENT, RIGHT_ALIGNMENT, TOP_ALIGNMENT

y los métodos:

action, add, addComponentListener, addFocusListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addPropertyChangeListener, addPropertyChangeListener, bounds, checkImage, checkImage, coalesceEvents, contains, contains, createImage, createImage, disable, disableEvents, dispatchEvent, enable, enable, enableEvents, enableInputMethods, firePropertyChange, getBackground, getBounds, getBounds, getColorModel, getComponentOrientation, getCursor, getDropTarget, getFont, getFontMetrics, getForeground, getGraphics, getHeight, getInputMethodRequests, getLocation, getLocation, getLocationOnScreen, getName, getParent, getPeer, getSize, getSize, getTreeLock, getWidth, getX, getY, gotFocus, handleEvent, hasFocus, hide, imageUpdate, inside, isDisplayable, isDoubleBuffered, isEnabled, isFocusTraversable, isLightweight, isOpaque, isValid, isVisible, keyDown, keyUp, list, list, list, location, lostFocus, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paintAll, prepareImage, prepareImage, printAll, processComponentEvent, processFocusEvent, processInputMethodEvent, processKeyEvent, processMouseEvent, processMouseMotionEvent, removeComponentListener, removeFocusListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, repaint, requestFocus, reshape, resize, resize, setBackground, setBounds, setBounds, setComponentOrientation, setCursor, setDropTarget, setEnabled, setForeground, setLocale, setLocation, setLocation, setName, setSize, setSize, setVisible, show, size, toString, transferFocus

Y, por lo tanto, los de Object:
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

La jerarquía es:



Preparamos otro pequeño aplique llamado Info.java

import java.applet.*;
import java.awt.*;
import java.awt.image.*;

public class Info extends Applet implements ImageObserver
{


public Info()
{

}

public void init()
{
super.init();
setBackground(Color.yellow);
resize(400,200);
}


public void start()
{
super.start();
}

public void stop()
{
super.stop();
}


public void destroy()
{
super.destroy();
}


public void paint (Graphics g)
{
g.setColor(Color.darkGray);

String p=getAppletInfo();

if (p!=null) g.drawString(p,10,10);

g.drawString("CODE:"+getCodeBase().toString(),10,20);

g.drawString("DOC:"+getDocumentBase().toString(),10,30);

Image io=getImage(getCodeBase(),"me.JPG");

// Para visualizar esta imágen necesito que Info implemente la interfaz ImageObserver.
// g.drawImage(Image,x,y,ImageObserver);
g.drawImage(io,10,40,this);

g.drawString("éste soy yo",80,80);

String nome=getParameter("pámetro3");

String cognome=getParameter("parámetro2");

String eta=getParameter("parámetro1");

g.drawString("Pone en marcha el programma",10,150);

g.drawString(nombre,10,160);

g.drawString(apellidos,10,170);

g.drawString("de "+edad+" años",10,180);

}

public String getAppletInfo()
{
return "Applet de Pietro Castellucci";
}

public String[][] getParameterInfo()
{

String[][] r={
{"parámetro1","entero","Tu edad"},
{"parámetro2","Cadena", "Tus Apellidos"},
{"parámetro3","Cadena","Tu Nombre"}
};
return r;
}

}

Para cargar el aplique vamos a crear un archivo llamado Info.html, que incluye:

<html>
<head>
<title>Info.html carga Info.class</title>
</head>
<body>
ëste es el aplique Info.
<BR>
<applet code="Info.class" width=400 height=200>
<param name=parámetro1 value=" EDAD DEL QUE PONE EN MARCHA EL PROGRAMA ">
<param name=parámetro2 value=" APELLIDOS DEL QUE PONE EN MARCHA EL PROGRAMA ">
<param name=parámetro3 value=" NOMBRE DEL QUE PONE EN MARCHA EL PROGRAMA ">
¡Tu browser es viejo, hay que cambiarlo!
</APPLET>
</body>
</html>

Cuidado con especificar los parámetros parámetro1, parámetro2 y parámetro3 porque en el aplique no se hace ningún control de sus definiciones. Por lo tanto, el aplique hace una excepción no capturada, además en el directorio donde ponéis el aplique, tiene que haber un archivo llamado me.JPG, que es una imágen 67x88 pixel.





Aplicaciones mixtas


 
Llegados a este punto, después de haber visto qué son los Frame y los Applet, se nos ocurre una pregunta. ¿Es posible combinar las dos técnicas, para invocarlas de alguna forma, para crear unas aplicaciones mixtas?
La respuesta, obviamente, es sí. Podemos hacer programas que son mixtos, una combinación de las aplicaciones y los apliques. Realmente, debido a la modularidad del lenguaje, podemos crear unas aplicaciones Java que utilizan otras aplicaciones, lo que no ocurre en los normales lenguajes de programación, donde es simplemente posible invocar programas de otro programa.
Supongamos, por ejemplo, que creamos un programa Java llamado Calculadora.java, con su main y sus métodos, entre los que hay uno que coge dos enteros y devuelve la suma.
Supongamos entonces, que lo redactamos en Calculadora.class y que lo incluímos ya puesto en marcha.
Por último hacemos otro programa de cualquier tipo en el que podemos utilizar el programa Calculadora.class, es decir la clase Calculadora y todas sus funciones públicas, entre ellas la de suma.

Volviendo al tema de los apliques que llaman de los frame, fijaos en este ejemplo:

import java.awt.*;
import java.applet.*;

public class Mixta extends Applet
{

Frame F;

public void init()
{

F = new Frame("Hola, éste es un Frame");

F.setSize(100,50);

F.show();

}

public void paint(Graphics g)
{

g.drawString("Yo soy un aplique",10,20);

new p();

}


public void destroy()
{

String [] param={""};

Ventana.main(param);

}


}



class p extends Frame
{

p()
{
setTitle("Otro Frame puesto en marcha por el aplique");

setSize(250,100);

setLocation(200,300);

show();

new Dialog(this,"Ésta es una dialog");

}

public void paint(Graphics g)
{

g.drawString("Podría ser un banner publicitario",10,40);



}


}

Lo ponéis en un archivo llamado Mixta.java, y lo pondréis en marcha creando un archivo Mixta.html que incluye:

<html>
<head>
<title>mixta</title>
</head>
<body>
Lo siguiente es un aplique:<BR>
<applet code="Mixta.class" width=200 height=100>¡Tu browser es viejo, tienes que cambiarlo!</APPLET>
</body>
</html>

Ponedlo en marcha y a ver lo que ocurre. Siempre el aplique pasa en segundo plano, es decir, coloca otra ventana encima, y despúes vuelve al primer plano.




Interfaces gráficas: GUI e AWT


 
Antes de empezar éste que es uno de los capítulos más interesantes del curso, introducimos el paquete awt y explicamos qué es un componente GUI.
Veremos también unos componentes que son contenedores para otros componentes.
El paquete Abstract Window Toolkit pone a disposición del programador una serie de clases e interfaces gráficas.
El paquete java.awt incluye también unos subpaquetes que son:

java.awt.color
java.awt.datatransfer
java.awt.dnd
java.awt.event
java.awt.font
java.awt.geom
java.awt.im
java.awt.image
java.awt.image.renderable
java.awt.print

Analizaremos algunas funciones. Las clases del paquete swing han sido construidas sobre las clases awt. Swuing es actualmente el paquete más utilizado para construir interfaces gráficas y las veremos enseguida.
Awt incluye:

Interfaces ActiveEvent, interfaces para sucesos que saben cómo se han activado.
Adjustable, interfaces para objetos que tienen un valor numérico entre una serie de valores.
Composite, interfaz que sirve para redactar las primitivas gráficas de awt.
CompositeContext, ambiente optimizado para las operaciones de composición de primitivas.
ItemSelectable, interfaz para objetos que incluyen un conjunto de item de los que pueden ser
seleccionados cero o más de uno. (Generalmente se pueden seleccionar por lo menos y al máximo un item. Esta interfaz elimina esta limitación).
LayoutManager, interfaz para las clases que incluirán unos gestores de ajuste de página.
LayoutManager2, como arriba.
MenuContainer, superclase de todos los menús.
Paint, esta interfaz define los colores que hay que utilizar para las operaciones gráficas usando Graphics2D.
PaintContext, ambiente optimizado para las operaciones de redacción de primitivas gráficas usando
Graphics2D.
PrintGraphics, define el contexto para imprimir.
Shape, definicciones para construir una forma geométrica.
Stroke, más decoraciones para las formas.
Transparency, define los tipos más comunes de transparencia.

Clases
AlphaComposite, clase que implementa las composiciones del factor alfa de los colores utilizando el blending y la transparecia de gráfica y las imágenes.
AWTEvent, root de los sucesos de AWT.
AWTEventMulticaster, dispatcher para suceos AWT, eficaz y multiprogramable. Hace el multicast de sucesos a varios componentes.
AWTPermission, para los permisos AWT.
BasicStroke, atributos para las líneas externas de las primitivas gráficas.
BorderLayout, es el primer gestor de ajuste de línea. Estos gestores, que analizaremos dentro de muy poco, sirven apra disponer los elementos (los componentes) en los contenedores. Éste divide el contenedor en 5 partes: norte, sur, este, oeste y centro.
Button, clase de los botones.
Canvas, área en la que se puede dibujar una aplicación.
CardLayout, otro gestor de layout.
Checkbox, CheckboxGroup, CheckboxMenuItem gestionan los botones de tipo booleano (apretado o no apretado)
Choice, presenta un menú a cortina para elegir.
Color, colores en RGB o en otros espacios arbitrarios de colores.
Component, Clase de la que derivan todos los componentes GUI (pulsadores, etiquetas,…)
ComponentOrientation, orientación de los componentes.
Container, contenedor de los componentes.
Cursor, cursores.
Dialog, ventanas de diálogo en las que se indican errores y no sólo eso.
Dimension, cajas que gestionan el tamaño de los componentes, la altura y la anchura.
Event, clase que gestiona los sucesos según el viejo modelo de gestión de los sucesos (Java 1.0). Se ha dejado para que se puedan trabajar las viejas aplicaciones y apliques Java y se declara deprecated. En efecto, este modelo se ha cambiado porque, en situaciones complejas, es decir, con muchos componentes puestos unos encima de otros, no se entendía qué componente recibía el suceso.
EventQueue, cola de sucesos.
FileDialog, dialog especial que gestiona el input y el output del archivo. Es muy cómoda.
FlowLayout, otro gestor del ajuste de línea.
Font, fonts para el texto.
FontMetrics, atributos para las font.
Frame, clase ya analizada que implementa las ventanas con título y marco.
GradientPaint, rellena las figuras con colores lineares.
Graphics, contexto gráfico en el que se puede dibujar.
Graphics2D, nuevo contexto gráfico, incluido con Java 2, que da otras sofisticadas posibilidades al dibujo.
GraphicsConfiguration, describe las características del destino de la gráfica que puede ser el monitor o la impresora.
GraphicsConfigTemplate, utilizada para obtener una GraphicsConfiguration válida.
GraphicsEnvironment, describe los ambientes gráficos y los font que se pueden utilizar para cada específica plataforma de Java.
GraphicsDevice, describe el GraphicDevice que se puede utilizar en un cierto ambiente.
GridBagConstraints, GridBagLayout, GridLayout, gestores del ajuste de línea.
Image, superclase para todas las clases que representan una imágen gráfica.
Insets, representa el borde de un contenedor.
Label, etiqueta.
List, listado
MediaTracker, clase de utilidad para gestionar objetos multimediales.
Menu, menú de tipo pull-down (a descenso).
MenuBar, barra de los menús.
MenuComponent, superclase de todos los componentes de los menús.
MenuItem, Voz de menú.
MenuShortcut, sirve para representar el acelerador para una voz de menú.
Panel, contenedor.
Point, punto en las coordenadas x,y.
Polygon, polígono.
PopupMenu, menú de tipo invisible.
PrintJob, sirve para inicializar y para imprimir.
Rectangle, rectángulo.
RenderingHints, incluye ayudas para el rendering utilizadas por Graphics2D.
RenderingHints.Key, define las teclas utilizadas para controlar los diferentes aspectos del rendering.
Scrollbar, barra de desplazamiento.
ScrollPane, panel con dos barras de desplazamiento.
SystemColor, representa los colores simbólicos de un objeto GUI en un sistema.
TextComponent, superclase de todos los componentes que incluyen el texto.
TextArea, área de testo.
TextField, simple línea de texto.
TexturePaint, cómo rellenar una figura con una texture.
Toolkit, superclase del Abstract Window Toolkit.
Window, ventana (sin borde y barra de menú).

Excepciones
AWTException
IllegalComponentStateException

Errores
AWTError

Visto este recorrido panorámico por el paquete informático, intentaremos comprender para qué sirven estas clases.
Entre todas las clases distinguimos algunas según lo que hacen.
En primer lugar, hemos visto unas clases Frame, Dialog e Windows, que representan unas ventanas. Estas ventanas incluyen unos menús (las primeras dos) y unos componentes GUI y para incluirlos hay que tener unos contenedores. Pertenecen a este tipo Container y Panel. Cada Contenedor puede incluir un Layout Manager que gestiona la colocación de varios componentes en el mismo contenedor y puede incluir incluso otros contenedores, que pueden crear estructuras complejas.
Finalmente hemos visto los verdaderos componentes GUI que se añaden a los contenedores, por ejemplo, Label. En el ejemplo que ponemos a continuación añadimos una label al contenedor del Frame.

import java.awt.*; public class Etiqueta extends Frame
{

Label et=new Label();

public Etiqueta(String etiqueta)
{


et.setText(etiqueta);
setTitle("Etiqueta "+etiqueta);
add(et);
pack();
show();

}

public static void main (String[] a)
{

try
{new Etiqueta(a[0]);}
catch (ArrayIndexOutOfBoundsException e)
{System.out.println("ERROR: teclear java Etiqueta CADENA");};

}

}

Como ya hemos dicho, los GUI van tanto en los Frame como en Applet, por lo tanto se puede pensar en la versión applet del programa anterior.

import java.applet.*;
import java.awt.*;

public class ApplEtiqueta extends Applet
{

Label et=new Label();

public void init ()
{

et.setText("Hola");
add(et);


}


}

Se pondrá en un archivo llamado ApplEtiqueta.java y se invocará desde un archivo html que incluye:

<html>
<head>
<title>

</title>
</head>
<body>
<APPLET code="ApplEtiqueta.class" width=200 height=100>
</APPLET>
</body>
</html>

En el paquete swing todo es muy parecido, aunque la gestión de los contenedores es un poco diferente.




Las etiquetas y los botones


Empezamos este recorrido panorámico sobre los GUI. Para utilizar varios componentes en la misma ventana necesitamos uno o más contenedores. Éstos los analizaremos sucesivamente, sin embargo tendré que utilizarlos de vez en cuando en este apartado sin haberlos explicado.
Estoy seguro de que no tendréis problemas para comprender los programas porque usaré tanto los Layout como los Container de forma muy simple. Sin embargo os pido perdón si este procedimiento os puede causar algún inconveniente.
En particular, utilizaré los Panel o utilizaré unas constantes de la clase BorderLayout, que separa el Container, en este caso el Panel, en cinco zonas, NORTH, SOUTH, WEST, EAST e CENTER.
En esta lección analizaremos dos componentes, los más simples, las Label y los Botones. Las primeras no tienen ningún suceso asociado, mientras los segundos, según el tipo de botón, tienen dos tipos de sucesos asociados..

Etiquetas
Empezamos nuestra panorámica sobre los componentes analizando el primer elemento simple, la etiqueta, que, entre otras cosas, ya hemos utilizado. La etiqueta es un contenedor para un texto. Esta hace aparecer en la pantalla una simple línea de texto que el usuario no puede editar, y que, sin embargo, la aplicación puede cambiar.
La etiqueta, invocada en Java Label, se encuentra en el paquete java.awt. Por lo tanto para ser utilizada, nuestro programa tendrá que empezar una import java.awt.Label (para incluir sólo la clase Label del paquete), o import java.awt.* (para incluir todas las clases del paquete) internamente al programa que quiere utilizarla, por lo tanto, tendrá que declarar un objeto de tipo Label de la siguiente forma:

Label etiqueta = new Label();

o, si no ha sido importado el paquete java.awt:

java.awt.Label etiqueta = new Label();

La Label tiene tres constructores:

Label() , que construye una etiqueta vacía. Label(String text), que construye una etiqueta con texto Text, justificada a la izquierda. Label(String text, int alignment) , que construye una etiqueta con texto Texto, justificada con alignment. Los valores de alignment son: Label.LEFT, Label.RIGHT, y Label.CENTER.

Algunos métodos del objeto son:

int getAlignment(), da la justificación actual del objeto.
String getText() , da el texto incluido en el label.
void setAlignment(int alignment), cambia la justificación de la Label con alignment.
void setText(String text), ajusta el texto de la Label.

Además existe el método AccessibleContext getAccessibleContext(), que veremos cuando analicemos los contenedores. Realmente la Label es un contenedor de texto.
Label viene de la siguiente jerarquía:



Por lo tanto hereda los métodos de Object y los de java.awt.Component. Todos los componentes GUI se heredan de Component, por lo tanto, al final de la panorámica de los GUI hablaremos de Component que incluye métodos muy útiles para sus gestión. Por ejemplo, métodos para ajustar y obtener informaciones sobre tamaño, colores del fondo, colores del texto, bordes, etc… del componente.
A parte los métodos de Component, estamos listos para utilizar las Label en nuestos programas. Por ahora no pongo ningún ejemplo sobre el uso de las Label porque las veremos en el siguiente párrafo cuando hablemos de los botones.
El paquete swing pone a disposición una clase parecida llamada JLabel que es una extensión de Label, y que, a su vez, pone a disposición una amplia gama de funciones añadidas. Por ejemplo, es posible crear JLabel que tengan tanto un texto como una imagen.

Botones
Otro componente muy utilizado, y de simple realización es el botón. Es un poco más complicado de la Label porque puede recibir unos sucesos (Click el botón).
Los botones son de tres tipos: los normales, les Checkbox y los radiobutton. Empezamos con los primeros.
La clase que define los botones es Button java.awt y pone a disposición todos los métodos para gestionar el aspecto del botón. Los constructores de la clase son dos:

Button(), costruye un botón sin etiqueta;
Button(String txt), costruye un botón con etiqueta txt.

Algunos métodos de la clase son:

void addActionListener(ActionListener l), añade el botón a un objeto invocado.
ActionListener, que escucha los sucesos. Cuando se clique el botón, el suceso será gestionado por ActionListener.
AccessibleContext getAccessibleContext(), como para las Label, los botones son también unos contenedores.
String getActionCommand(), a cada botón se asocia una órden que devuelve el actual.
String getLabel(), devuelve la etiqueta asociada al botón.
EventListener[] getListeners(Class listenerType), da un array que incluye a todos los que escuchan sucesos establecidos por este botón.
addXXXListener(), añade un oyente de sucesos de tipo tipo XXX. En Java hay varios tipos de sucesos, los analizaremos dentro de poco. Uno de éstos es el suceso de tipo action y, en este caso, el método es addActionListener( )
void removeActionListener(ActionListener l), elimina el oyente de sucesos 1 precedentemente asociado al botón.
void setActionCommand(String command), ajusta la órden asociada al botón. Al principio la órden es la etiqueta.
void setLabel(String label), ajusta la etiqueta del botón.

Ahora podemos definir nuestro primer botón. Sólo tenemos que conseguir entender cómo capturar el suceso que resulta de la presión del mismo. Como ya dicho anteriormente, trataré de la gestión de los suceos según Java 2 porque el viejo modelo de gestion de los eventos de Java 1 es obsoleto y no funciona.
Según Java2, definido un botón, como el suceso principal del botón es el click, que pertenece a la familia de los sucesos Action, hay que asociar un ActionListener al mismo botón utilizando el método addActionListaner(ActionListener l); Lo que tenemos que hacer es crear un ActionListener especializado para nuestro botón (o para nuestros botones).
ActionListener se define en el paquete java.awt.event (que hay que incluirlo en el programa). Es una interfaz y, por lo tanto, tiene que ser implementada en la clase en la que se ha definido.
Por ejemplo, estoy haciendo un Frame llamado Tribilín que incluye un botón del que quiero escuchar el click y quiero escucharlo con un ActionListener especializado por mí llamado EscuchaTribilín. Tendré que escribir algo parecido a:

import java.awt.*;
import java.awt.event.*;
public class Tribilín extends Frame
{
Button botón=new Button("Hola");
… métodos de Tribilín, entre los que está el constructor, que incluye un botón.addActionListener(new EscuchaTribilín());

public class EscuchaTribilin implements ActionListener()
{
// Gestión del suceso
} // Fin clase EscuchaTribilín dentro de Tribilín
}//Fin clase Tribilín

En EscuchaTribilín tendré que especializar todos los métodos de la interfaz que estoy extendiendo. ActionListener tiene sólo un método:

void actionPerformed(ActionEvent e), por lo tanto, en EscuchaTribilón tendré que definir el método public void actionPerformed(ActionEvent e). Éste es el método que se invocará cuando clique el botón.
La ActionEvent que llega al método como parámetro, incluye todas las informaciones sobre el suceso, incluso la órden. EscuchaTribilín se puede asociar incluso a más botones. Su actionPerformed se invocará al click de cada uno de estos botones. Aclaremos en seguida este concepto que, a lo mejor, es un poco más difícil de las demás cosas que hemos hecho con el anterior ejemplo. Sin embargo, os aseguro que una vez asimilado el concepto, la gestión de los sucesos de Java resultará muy simple.
Creamos un Frame que tenga un botón y una Label: cada vez que se clica el botón, la etiqueta da un mensaje.

import java.awt.*;
import java.awt.event.*;

public class Botón extends Frame
{
// Constructor clase Botón

Button clícame=new Button("Clícame");

Label clicado=new Label("No me has clicado ni siquiera una vez");

public Botón()
{
clícame.addActionListener(new Oyente());
// setup comando
clícame.setActionCommand("CLIC");
// Añado un botón y la etiqueta al Frame.
// No hagáis caso a las siguientes instrucciones,
// la add sirve para añadir un componente ad
// un contenedor y el segundo parámetro
// add, es decir BorderLayout, es un gestor de Layout,
// que sirve para establecer la forma en la que los objetos
// GUI se colocan en el contenedor.

add(clícame,BorderLayout.NORTH);
add(clicado,BorderLayout.SOUTH);


// métodos de Frame
pack();
show();
}

// main

public static void main (String [] arg)
{

new Botón();

}

// Oyente de suceso Action

int Volte=2;

public class Oyente implements ActionListener
{

public void actionPerformed (ActionEvent e)
{

String Órden=e.getActionCommand();

if (Órden.compareTo("CLIC")==0)
{

clicado.setText("Me has clicado");

clícame.setLabel("Vuelve a clicarme");

clícame.setActionCommand("RECLIC");

};

if (Órden.compareTo("RECLIC")==0)
clicado.setText("Me has clicado "+(Veces++)+" veces.");

}

}// Fin Oyente

}// Fin Botón


El resultado es la siguiente ventana:






Como se ve en Oyente se gestionan dos órdenes diferentes asociados al mismo botón y éste, cuando se clica por primera vez, cambia la órden asociado al suceso clic.
Intentad cambiarlo modificando la orden para estalblecer con certeza las primeras diez veces que se clica e imprimiendo en la etiqueta "Has clicado nueve veces el botón" (la novena vez).

Resumiendo, en una interfaz gráfica, en primer lugar se programa el aspecto gráfico, es decir, se incluyen los botones, los menús, etc. Después se crean y se añaden los oyentes de los sucesos que, según el suceso, invocan uno u otro método de gestión del programa (pone al día la interfaz, calcula las funciones del programa de la que es la interfaz gráfica).
Éste es un principio general de la programación de Interfaces Gráficas, es decir, de la programación de los sucesos. Cada programa que utilizáis funciona de esta forma y cada programa que escribíss también.
El tipo de programación es un poco diferente al que un programador sobre plataforma no gráficas (tipo Dos, Linux senza X-Win) está acostumbrado y al principio puede resultar no muy simple. Sin embargo hay que acostumbrarse, después es todo igual.

El segundo tipo de botones que analizamos son las Checkbox, es decir, los botones de tipo booleano, que retienen el estado. Se utilizan para hacer opciones no exclusivas o exclusivas entre ellas (en este último caso son unos radiobutton). Por ejemplo, si hay que elegir entre unos hobbies preferidos, estos botones, una vez clicados, se quedan así y hay que volver a clicarlos para que vuelvan a la situación inicial.
Pra crear una Checkbox hay que crear un objeto que pertenece a la clase Checkbox de java.awt. Los constructores son:

Checkbox(), crea una Checkbox sin etiqueta.
Checkbox(String label), crea una Checkbox con etiqueta label.
Checkbox(String label, boolean state), crea una Checkbox con etiqueta label, y hay que clicarla o no según el valor booleano state.

En cambio para los radiobutton:

Checkbox(String label, boolean state, CheckboxGroup group), crea una Checkbox con etiqueta label introducida en una particular
CheckboxGroup, que es un contenedor de Checkbox.
Checkbox(String label, CheckboxGroup group, boolean state) crea una Checkbox con etiqueta label introducida en una particular
CheckboxGroup, y ajustada según el valor de state.

Prácticamente, entre todos los botones introducidos en el CheckboxGroup, sólo uno puede ser clicado, los demás no se tienen que clicar. Las Checkbox del primer tipo, como he dicho, se utilizan para hacer unas opciones no exclusivas como, por ejemplo, la opción de los intereses entre una lista de los intereses posibles. Mientras las Checkbox del segundo tipo, es decir, los radiobuttons sirven para hacer opciones exclusivas como, por ejemplo, la opción de la renta de una persona en las diferentes fases.

Entre los métodos de la clase Checkbox los más interesantes son:

void addItemListener(ItemListener l) , asocia un ItemListener a la Checkbox, el ItemListener gestiona los sucesos de los Checkbox y no sólo eso. Son un segundo tipo de sucesos que aprenderemos a utilizar. De todas formas, se parecen a los ActionListener, lo único es que se asocian a los objetos que tienen un estado.
CheckboxGroup getCheckboxGroup(), da el posible grupo en el que se intruduce la Checkbox.
Las ya conocidas String getLabel() e EventListener[] getListeners(Class listenerType) boolean getState(), este método dice que la Checkbox se ha clicado o no.
void removeItemListener(ItemListener l), quita el actual oyente de sucesos Item.
void setCheckboxGroup(CheckboxGroup g), ajusta un gruppo para la Checkbox.
void setLabel(String label), ajusta la etiqueta
void setState(boolean state), ajusta el estado.

Vamos a ver ahora lo que contiene un CheckboxGroup. El constructor no tiene parámetros y los métodos no declarados Deprecated son tres:

Checkbox getSelectedCheckbox(), da la Checkbox seleccionada en el grupo .
void setSelectedCheckbox(Checkbox box), ajusta la Checkbox del grupo indicado.
String toString(), da una cadena que representa el objeto.

Ahora vamos a poner un pequeño ejemplo que usa tanto Checkbox como RadioButton.

import java.awt.*;
import java.awt.event.*;

public class Check extends Frame
{
// Constructot clase Botón

Label r=new Label("Renta anual");
Label i=new Label("Intereses");

Button sale=new Button("saledela aplicación");

CheckboxGroup renta=new CheckboxGroup();

Checkbox r1=new Checkbox("De 0 a 10");
Checkbox r2=new Checkbox("De 11 a 30");
Checkbox r3=new Checkbox("De 31 a 70");
Checkbox r4=new Checkbox("De 71 a 100");
Checkbox r5=new Checkbox("De 101 a 200");
Checkbox r6=new Checkbox("De 201 a 500");
Checkbox r7=new Checkbox("Soy un ricachón");

Checkbox i1=new Checkbox("Esport");
Checkbox i2=new Checkbox("Informática");
Checkbox i3=new Checkbox("Lectura");
Checkbox i4=new Checkbox("Cine");
Checkbox i5=new Checkbox("Animales");
Checkbox i6=new Checkbox("Teveos");
Checkbox i7=new Checkbox("Loterías");
Checkbox i8=new Checkbox("Mujeres");
Checkbox i9=new Checkbox("Hombres");



public Check()
{
sale.addActionListener(new Oyente());


Panel p1=new Panel();

Panel p2=new Panel();

p1.add(r);
p1.add(r1);
p1.add(r2);
p1.add(r3);
p1.add(r4);
p1.add(r5);
p1.add(r6);
p1.add(r7);

r1.setCheckboxGroup(renta);
r2.setCheckboxGroup(renta);
r3.setCheckboxGroup(renta);
r4.setCheckboxGroup(renta);
r5.setCheckboxGroup(renta);
r6.setCheckboxGroup(renta);
r7.setCheckboxGroup(renta);



add(p1,BorderLayout.NORTH);


p2.add(i);
p2.add(i1);
p2.add(i2);
p2.add(i3);
p2.add(i4);
p2.add(i5);
p2.add(i6);
p2.add(i7);
p2.add(i8);
p2.add(i9);



add(p2,BorderLayout.CENTER);

add(sale,BorderLayout.SOUTH);

// métodos de Frame

pack();
show();

}

// main

public static void main (String [] arg)
{

new Check2();

}


// Oyentes de sucesos Action

public class Oyente implements ActionListener
{

public void actionPerformed (ActionEvent e)
{

System.out.println("afiliación al sito XXXXXXX.it");

System.out.print("ganancia anual ");
if (r1.getState()) System.out.println(r1.getLabel());
else if (r2.getState()) System.out.println(r2.getLabel());
else if (r3.getState()) System.out.println(r3.getLabel());
else if (r4.getState()) System.out.println(r4.getLabel());
else if (r5.getState()) System.out.println(r5.getLabel());
else if (r6.getState()) System.out.println(r6.getLabel());
else if (r7.getState()) System.out.println(r7.getLabel()+" (Qué suerte!)");
else System.out.println("NO DECLARADO");

System.out.println("Intereses declarados:");
if (i1.getState()) System.out.println("t"+i1.getLabel());
if (i2.getState()) System.out.println("t"+i2.getLabel());
if (i3.getState()) System.out.println("t"+i3.getLabel());
if (i4.getState()) System.out.println("t"+i4.getLabel());
if (i5.getState()) System.out.println("t"+i5.getLabel());
if (i6.getState()) System.out.println("t"+i6.getLabel());
if (i7.getState()) System.out.println("t"+i7.getLabel());
if (i8.getState()) System.out.println("t"+i8.getLabel());
if (i9.getState()) System.out.println("t"+i9.getLabel());

System.exit(0);
}

}// Fin Oyente

}// Fin Botón

Fig 4: Ventana del programa

He tenido que usar otra vez los layout y también los Panel. Lo siento porque todavía no los hemos tratado, sin embargo, es la única forma para introducir más GUI en la misma ventana. Por ejemplo, intentad quitar los Panel y, sucesivamente, añadid todo directamente a las ventanas, sin utilizar los Layout. Váis a ver lo que ocurre.
En la aplicación hay un botón que sirve para cerrar la ventana porque todavía no sabemos gestionar los sucesos de la ventana, como el close, que en este caso no funciona. Dentro de poco podremos gestionar incluso éstos.

En la aplicación no he gestionado los sucesos de las Checkbox porque no lo he necesitado. Hay situaciones en las que se tienen que gestionar, en las que, además del estado del botón cambia algo, por ejemplo, el estado de algún GUI. Lo vemos en este ejemplo.

import java.awt.*;
import java.awt.event.*;

public class Check2 extends Frame
{
// Constructot clase Botón


Button cierra=new Button("Sale de la aplicación");

Checkbox i1=new Checkbox("primeros 3");
Checkbox i2=new Checkbox("segundos 4");

Checkbox ii1=new Checkbox("uno");
Checkbox ii2=new Checkbox("dos");
Checkbox ii3=new Checkbox("tres");
Checkbox ii4=new Checkbox("cuatro");
Checkbox ii5=new Checkbox("cinco");
Checkbox ii6=new Checkbox("seis");
Checkbox ii7=new Checkbox("siete");



public Check2()
{
cierra.addActionListener(new Oyente());


Panel p1=new Panel();

Panel p2=new Panel();

p1.add(ii1);
p1.add(ii2);
p1.add(ii3);
p1.add(ii4);
p1.add(ii5);
p1.add(ii6);
p1.add(ii7);


ii1.addItemListener(new AItem1());
ii2.addItemListener(new AItem1());
ii3.addItemListener(new AItem1());
ii4.addItemListener(new AItem1());
ii5.addItemListener(new AItem1());
ii6.addItemListener(new AItem1());
ii7.addItemListener(new AItem1());


i1.addItemListener(new AItem2());
i2.addItemListener(new AItem2());

add(p1,BorderLayout.NORTH);

p2.add(i1);
p2.add(i2);



add(p2,BorderLayout.CENTER);

add(cierra,BorderLayout.SOUTH);

// métodos de Frame

pack();
show();

}

// main

public static void main (String [] arg)
{

new Check();

}


// Oyente de sucesos Action

public class Oyente implements ActionListener
{

public void actionPerformed (ActionEvent e)
{System.exit(0);}

}// Fin Oyente

// Oyente de sucesos Item
public class AItem1 implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{

i1.setState(ii1.getState()&&
ii2.getState()&&
ii3.getState());

i2.setState(ii4.getState()&&
ii5.getState()&&
ii6.getState()&&
ii7.getState());
}

}//Fin AItem1


public class AItem2 implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{
ii1.setState(i1.getState());
ii2.setState(i1.getState());
ii3.setState(i1.getState());
ii4.setState(i2.getState());
ii5.setState(i2.getState());
ii6.setState(i2.getState());
ii7.setState(i2.getState());
}

}//Fin AItem2


}// Fin Botón







Contenedores y Gestión de los Layout


 
En la lección anterior hemos visto como introducir en nuestras aplicaciones y en nuestros apliques unas etiquetas y unos botones. Para hacerlo hemos utilizado unos contenedores y unos layout sin saber cómo funcionaban. En este lección analizeremos sus funcionamientos y cómo aprovecharlos para mejorar nuestras interfaces.
Empezamos con describir la clase Container del paquete java.awt. Es una extensión de la clase Component de la que proceden todos los componentes GUI y, en realidad, éste mismo es un componente GUI.




Un Container es un contenedor para los objetos GUI y, por lo tanto, también para los demás container. Se utiliza junto a un Layout Manager y permite que abarquen más de un GUI (y Contenedores), permitiendo que aparezcan varios objetos en nuestras interfaces. Vemos qué contiene la clase.
Container() , es el único constructor de la clase.

Unos métodos: Component add(Component comp), añade el componente al final del contenedor.
Component add(Component comp, int index), añade el componente en la posición indicada por el contenedor.
void add(Component comp, Object constraints) e void add(Component comp, Object constraints, int index) , como antes, lo único es que especifica unas constantes para el componente que se ha introducido.
Component add(String name, Component comp), añade al contenedor el componente y le da un nombre.
void addContainerListener(ContainerListener l), ajusta el ContainerListener que escuchará los sucesos que han ocurrido en el contenedor.
void doLayout(), provoca la disposición de los componentes en el contenedor.
Component findComponentAt(int x, int y), devuelve el componente que se encuentra en la posición especificada del contenedor (posición gráfica).
Component findComponentAt(Point p) , devuelve el componente que se encuentra en la posición especificada del contenedor (posición gráfica).
float getAlignmentX(), devuelve el ajuste de líneas a lo largo del eje X del contenedor.
float getAlignmentY(), devuelve el ajuste de líneas a lo largo del eje Y del contenedor.
Component getComponent(int n), devuelve el enésimo componente introducido en el contenedor.
Component getComponentAt(int x, int y), devuelve el componente que se encuentra en la posición especificada del contenedor (posición gráfica).
Component getComponentAt(Point p), devuelve el componente que se encuentra en la posición especificada del contenedor (posición gráfica).
int getComponentCount() , da el número de componentes introducidos en el contenedor.

Component[] getComponents(), da todos los componentes introducidos en el contenedor.
Insets getInsets(), da un objeto Insets para el contenedor. Este objeto representa el tamaño (gráfico= del contenedor.
LayoutManager getLayout(), devuelve el LayuotManager asociado al contenedor.
EventListener[] getListeners(Class listenerType), devuelve todos los oyentes de sucesos al contenedor.
Dimension getMaximumSize(), devuelve el tamaño máximo que puede tener el contenedor.
Dimension getMinimumSize(), devuelve el tamaño mínimo que puede tener el contenedor.
Dimension getPreferredSize(), devuelve el tamaño preferido por el contenedor.
void list(PrintStream out, int indent), imprime el listado de los componentes introducidos en el contenedor, sobre un stream de output.
void list(PrintWriter out, int indent), imprime en una impresora los componentes introducidos en el contenedor.
void paint(Graphics g), dibuja el contenedor. La paint es una función muy importante. Veremos cómo definirla para dibujar en una ventana.
void paintComponents(Graphics g). dibuja todos los componentes del contenedor.
void print(Graphics g), imprime el contenedor (el aspecto gráfico).
void printComponents(Graphics g), imprime todos los componentes introducidos en el contenedor (sus aspectos gráficos).
void remove(Component comp), elimina el componente especificado por el contenedor.
void remove(int index), aparta el componente que se encuentra en la posición especificada en el contenedor.
void removeAll(), aparta todos los componentes introducidos en el contenedor.
void removeContainerListener(ContainerListener l), elimina el oyente de sucesos para containers de este container.
void setFont(Font f), ajusta las Font utilizadas por el texto en el contenedor.
void setLayout(LayoutManager mgr), asocia al contenedor un gestor de layout.
void update(Graphics g), vuelve a dibujar el contenedor.
void validate(), anula el contenedor y sus componentes.

Introduciendo componentes en el contenedor, como en el ejemplo sucesivo, nos damos cuenta de que sólo el último será visualizado. Esto ocurre porque no hemos dado gestor de Layout. En el caso de applet, en cambio, el LayoutManager de default es el FlowLayout.

import java.awt.*;

public class Contenedor extends Frame
{

Label l1=new Label("Etiqueta1");
Label l2=new Label("Etiqueta2");
Label l3=new Label("Etiqueta3");
Label l4=new Label("Etiqueta4");
Label l5=new Label("Etiqueta5");

public Contenedor()
{
// uso add, porque el Frame es una extensión de Window, que a su
// vez amplía Container.

add(l1);
add(l2);
add(l3);
add(l4);
add(l5);
doLayout();
pack();
show();
}

public static void main(String [] arg)
{

new Contenedor();

}

}

Por lo tanto, vemos cómo introducir un gestor de Layout en el contenedor. El método de la clase container que lo permite es void setLayout(LayoutManager mgr). No nos queda que ver cómo es el objeto de tipo LayoutManager.
LayoutManager es una interfaz. De las clases que la implementan analizaremos GridLayout, FlowLayout.
Hay otra interfaz llamada LayoutManager2, que amplía ésta y que tiene otras clases que la implementan. De éstas veremos: CardLayout, BorderLayout, GridBagLayout, BoxLayout, OverlayLayout.
Por lo tanto, en el método setLayout (…) podemos utilizar como parámetro un objeto de estas clases.
Llegados a este punto, tenemos que comprender qué diferencia hay entre los layout manager.
El FlowLayout deja colocar los componentes de un contenedor de la izquierda hacia la derecha en una sóla línea.




Para utilizar el LayoutManager FlowLayout del ejemplo precedente basta con invocar el método setLayout con parámetro new FlowLayout(), y después los componentes se introducen automáticamente, de la add de la derecha hacia la izquierda en la misma línea.

import java.awt.*;

public class ContEFL extends Frame
{

Label l1=new Label("Etiqueta1");
Label l2=new Label("Etiqueta2");
Label l3=new Label("Etiqueta3");
Label l4=new Label("Etiqueta4");
Label l5=new Label("Etiqueta5");

public ContEFL()
{
// uso add, porque el Frame es una extensión de Window, que a su
// vez amplía Container.

setLayout(new FlowLayout());

add(l1);
add(l2);
add(l3);
add(l4);
add(l5);

pack();
show();

}

public static void main(String [] arg)
{

new ContEFL();

}

}

La ventana que sale es:




El GridLayout permite colocar los componentes en un contenedor como si se dispusieran en una plantilla.




Todos los componentes tendrán el mismo tamaño. La clase tiene tres constructores, uno sin parámetros que crea una planilla con 1 línea, prácticamente un FlowLayout, y otros dos que permiten especificar el tamaño de la planilla.
El ejemplo anterior cambia de esta forma:

import java.awt.*;

public class ContEGL extends Frame
{

Label l1=new Label("Etiqueta1");
Label l2=new Label("Etiqueta2");
Label l3=new Label("Etiqueta3");
Label l4=new Label("Etiqueta4");
Label l5=new Label("Etiqueta5");

public ContEGL()
{
// uso add, poruqe el Frame es una extensión de Window, que a su
// vez amplía Container.

setLayout(new GridLayout(2,3));

add(l1);
add(l2);
add(l3);
add(l4);
add(l5);

pack();
show();

}

public static void main(String [] arg)
{

new ContEGL();

}

}

La ventana es la siguiente:




El LayoutManager CardLayout permite visualizar los componentes diferentes en plazos de tiempo diferentes, es decir, que visualiza sólo un componente a la vez. Sin embargo el componete visualizado se puede cambiar.
Hay aquí un ejemplo del uso de CardLayout

import java.awt.*;
import java.awt.event.*;

public class ContECL extends Frame
{

Label l1=new Label("Etiqueta1");
Label l2=new Label("Etiqueta2");
Label l3=new Label("Etiqueta3");
Label l4=new Label("Etiqueta4");
Label l5=new Label("Etiqueta5");

Panel p=new Panel(new GridLayout(2,1));
CardLayout CL=new CardLayout(14,14);
Panel p1=new Panel(CL);
Panel NPB=new Panel(new FlowLayout());

public ContECL()
{



p.add(NPB);
p.add(p1);

Button N=new Button("Próximo");
Button P=new Button("Anterior");

NPB.add(P);
NPB.add(N);

P.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
CL.previous(p1);
}
}
);

N.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
CL.next(p1);
}
}
);

p1.add("uno",l1);
p1.add("dos",l2);
p1.add("tres",l3);
p1.add("cuatro",l4);
p1.add("cinco",l5);

add(p);
pack();
show();

}

public static void main(String [] arg)
{

new ContECL();

}

}

El resultado de los ejemplos son las siguientes ventanas:











Muestran como las cinco etiquetas aparecen en la misma posición en plazos de tiempo diferentes.
Notad que en el ejemplo no se han utilizado los demás gestores de Layout para que se puedan introducir los botones Próximo y Anterior.

BorderLayout es uno de los gestores de Layout más utilizados. Permite introducir en un contenedor cinco componentes, uno al Norte, uno al Sur, uno al Este, uno al Oeste y otro al Centro.
El tamaño del contenedor lo establecerá el componente central. Las cinco posiciones están indicadas por los contenedores de la clase:

BorderLayout.NORTH
BorderLayout.SOUTH
BorderLayout.EAST
BorderLayout.WEST
BorderLayout.CENTER

hay aquí un ejemplo del uso de BorderLayout. He cambiado los colores de fondo de las etiquetas para que se vea el componente entero.

import java.awt.*;

public class ContEBL extends Frame
{

Label l1=new Label("Etiqueta al Norte",Label.CENTER);
Label l2=new Label("Etiqueta al Sur",Label.CENTER);
Label l3=new Label("Etiqueta al Este",Label.CENTER);
Label l4=new Label("Etiqueta al Oeste",Label.CENTER);
Label l5=new Label("Etiqueta al Centro",Label.CENTER);

public ContEBL()
{
// uso add porque el Frame es una extensión de Window, que a su
// vez amplía Container.

l1.setBackground(Color.pink);
l2.setBackground(Color.lightGray);
l3.setBackground(Color.green);
l4.setBackground(Color.yellow);
l5.setBackground(Color.orange);


setLayout(new BorderLayout());

add(l1,BorderLayout.NORTH);
add(l2,BorderLayout.SOUTH);
add(l3,BorderLayout.EAST);
add(l4,BorderLayout.WEST);
add(l5,BorderLayout.CENTER);

pack();
show();

}

public static void main(String [] arg)
{

new ContEBL();

}

}

El resultado es:




Hay también otros gestores de Layout, que no analizaremos, y que, sin embargo, podéis estudiar junto a éstos en la documentación oficial de las Java Development Kit.




Menús


Un menú en una aplicación no es más que un MenuBar en el que hay varios menús.
Pensemos en un programa cualquiera con las voces de menú File Edit y Help. Estas tres voces en Java son unos objetos de la clase Menú y se tienen que añadir a un objeto de la clase MenuBar que se une a la ventana. Cada menú tiene varias voces. por ejemplo, el menú File tendrá las voces: Abrir, Cerrar, Guarda y Salir. Éstos en Java son unos objetos de la clase MenuItem (o también Menú si incluyen otros submenús).




Por lo tanto, si a una aplicación le quisieramos añadir un menú tendríamos hacer las siguientes cosas siguiendo un órden cualquiera:

Crear los objetos MenuItem
Crear los objetos menú y pegarles los MenuItem
Crear una MenuBar y pegarles los Menús

Además, como siempre, tenemos que escribir unos gestores para los sucesos de los menús y asociarlos a los menús.
Veamos, en práctica, cómo se construye un menu, empezando por los MenuItem.
Los sucesos de los MenuItem son los que tenemos que gestionar nosotros a diferencia de los sucesos de los menús que los gestiona el sistema. Mientras los segundos sirven para que aparezcan y desaparezcan las voces del menú, los primeros son los clics sobre la orden correspondiente al Item.
Por lo tanto, para éstos tendremos que escribir unos ActionListener, como para los botones. Realmente no son otra cosa que unos botones especiales. Los constructores son tres:

MenuItem() , que construye un MenuItem sin etiqueta.
MenuItem(String label), que construye MenuItem con etiqueta label.
MenuItem(String label, MenuShortcut s), que construye un MenuItem con etiqueta label y acelerador (tecla de opción rápida) definido en MenuShortcut s.

Algunos métodos son:

addActionListener(ActionListener l), asocia un ActionListener al MenuItem para escuchar los sucesos de tipo ActionEvent (el clic).
void deleteShortcut(), borra la tecla de opción rápida para el menuitem.
String getActionCommand(), da la acción asociada al MenuItem. La acción es la que pasa al actionListener del botón para identificar el botón mismo. Así varios item pueden tener el mismo gestor de sucesos que podrá distinguir el botón clicado basándose en la órden que le llega.
String getLabel(), devuelve la etiqueta del MenuItem
EventListener[]getListeners(Class listenerType) , devuelve todos los oyentes de sucesos asociados al MenuItem, del tipo listenerType.
MenuShortcut getShortcut(), devuelve la definición del acelerador para el MenuItem.
boolean isEnabled(), dice si el menú esta disponible o no. Si no lo está se visualizará en gris.
void removeActionListener(ActionListener l), elimina el oyente asociado.
void setActionCommand(String command), ajusta la orden asociada al MenuItem. Si no está especificado, la órden es la etiqueta del MenuItem.
void setEnabled(boolean b), habilita y deshabilita el MenuItem.
void setLabel(String label), ajusta la etiqueta para el MenuItem.
void setShortcut(MenuShortcut s), define el acelerador para el menú.

Por lo tanto, para crear los Item del menú File descrito antes tendremos que escribir:

MenuItem abrir=new MenuItem("Abrir");
MenuItem cerrar=new MenuItem("Cerrar");
MenuItem guardar=new MenuItem("Guardar");
MenuItem salir=new MenuItem("Salir");

Por tanto creamos el objeto Menu para pegar los MenuItem.
Dos constructores del objeto son:

Menu(), construye un Menú sin etiqueta
Menu(String label), construye un menú con etiqueta label.

Entre los métodos hay:

MenuItem add(MenuItem mi), añade un MenuItem al Menú.
void add(String label), añade una etiqueta al Menú (tipo separador).
void addSeparator(), añade un verdadero separador al menú, es decir, una línea.

Añadiendo objetos a un menú de esta forma, se colocarán en el mismo órden en el que se añaden. Para especificar, en cambio, la posición en que si quieren introducir hay que usar los métodos:

void insert(MenuItem menuitem, int index)
void insert(String label, int index)
void insertSeparator(int index)

Los métodos MenuItem getItem(int index) e int getItemCount() sirven para coger un item establecido en una posición y para conocer el número de MenuItem incluidos en un menú.

Para eliminar los Item del menú, en cambio, se utilizan los métodos:

void remove(int index)
void remove(MenuComponent item) e
void removeAll()
Por lo tanto, para crear nuestro menú File tendremos que escribir:
Menu file= new Menu("File");
file.add(abrir);
file.add(guardar);
file.add(cerrar);
file.addSeparator();
file.add(salir);

Llegados e este punto, suponiendo haber creado también Edit y Help, tenemos que añadirle el MenuBar que se crea utilizando el constructor MenuBar().
En esta barra estan los métodos remove y removeAll como para los menús, y está la add:

Menu add(Menu m);

Por lo tanto nuestro MenuBar se tendrá que crear de la siguiente forma:

MenuBar barra=new MenuBar();
barra.add(file);
barra.add(edit);
barra. setHelpMenu(help);

Este último método es especial para añadir un menú de ayuda.

Finalmente, no nos queda que asociar la barra de menú a nuestra ventana. Esto es muy simple porque nuestra ventana será una extensión de Frame y en frame está el método:

setMenuBar(MenuBar mb);

En nuestro caso será setMenuBar (barra);
CUIDADO: con awt no es posible introducir menú en Dialog y en Applet (los que se ven son falsos menús, es decir, se programan dibujando unos menús o no son sólo awt), mientras con swing sí.
A continuación mostramos el listado de una aplicación que define un menú y escucha los sucesos:

import java.awt.*;
import java.awt.event.*;

public class Ventanamenú extends Frame
{

MenuItem abrir=new MenuItem("Abrir");
MenuItem cerrar=new MenuItem("Cerrar");
MenuItem salvar=new MenuItem("Guardar");
MenuItem salir=new MenuItem("Salir");

MenuItem cortar=new MenuItem("Cortar");
MenuItem copiar=new MenuItem("Copiar");
MenuItem pegar=new MenuItem("Pegar");
MenuItem eliminar=new MenuItem("Eliminar");

MenuItem buscar=new MenuItem("Buscar");
MenuItem sustituir=new MenuItem("Sustituir");

MenuItem ayuda=new MenuItem("Índice");


Menu file= new Menu("File");
Menu edit= new Menu("Edit");
Menu help= new Menu("Help");

MenuBar barra = new MenuBar();

Label resultado=new Label("Ninguna voz de menú clicada");

public Ventanamenú()
{

setupSucesos();

file.add(abrir);
file.add(guardar);
file.add(cerrar);
file.addSeparator();
file.add("Menú Salir");
file.addSeparator();
file.add(salir);

edit.add(cortar);
edit.add(copiar);
edit.add(pegar);
edit.add(eliminar);
edit.addSeparator();
edit.add(buscar);
edit.add(sustituir);

help.add(ayuda);

barra.add(file);
barra.add(edit);
barra.setHelpMenu(help);

setMenuBar(barra);

add(resultado);

pack();
show();
addWindowListener(new VentanamenúWindowListener());
}

void setupSucesos()
{
abrir.addActionListener(new OyenteMenú());
salvar.addActionListener(new OyenteMenú());
cerrar.addActionListener(new OyenteMenú());
salir.addActionListener(new OyenteMenú());

cortar.addActionListener(new OyenteMenú());
copiar.addActionListener(new OyenteMenú());
pegar.addActionListener(new OyenteMenú());
eliminar.addActionListener(new OyenteMenú());

buscar.addActionListener(new OyenteMenú());
sustituir.addActionListener(new OyenteMenú());

ayuda.addActionListener(new OyenteMenú());


}


public static void main(String[] arg)
{

new Ventanamenú();

}

class OyenteMenú implements ActionListener
{

public void actionPerformed (ActionEvent e)
{

resultado.setText(" Clicado "+e.getActionCommand());
if (e.getActionCommand().compareTo("Salir")==0) System.exit(0);

}

}
class VentanamenúWindowListener implements WindowListener
{

public void windowActivated(WindowEvent e)
{
System.out.println("Escuchado un Window Activated");
}

public void windowClosed(WindowEvent e)
{
System.out.println("Escuchado un Window Closed");
}

public void windowClosing(WindowEvent e)
{
System.out.println("Escuchado un Window Closing");
System.exit(0);
}

public void windowDeactivated(WindowEvent e)
{
System.out.println("Escuchado un Window Deactivaded");
}

public void windowDeiconified(WindowEvent e)
{
System.out.println("Escuchado un Window Deiconified");
}

public void windowIconified(WindowEvent e)
{
System.out.println("Escuchado un Window Iconified");
}

public void windowOpened(WindowEvent e)
{
System.out.println("Escuchado un Window Opened");
}

}

}

Como acabamos de ver en el ejemplo, hay otro oyente de sucesos. Escucha los sucesos de tipo WindowEvent y sirve para escuchar sucesos de la ventana.
Para asociarlo a la ventana se utiliza el método addWindowListener(WindowListener l); en el que WindowListener es el oyente de los sucesos. Para definir un oyente de sucesos hay, por lo tanto, que implementar la interfaz WindowListener y volver a definir todos los métodos:

class MÍOYENTE implements WindowListener

Los métodos para definir son:

public void windowActivated(WindowEvent e)
public void windowClosed(WindowEvent e)
public void windowClosing(WindowEvent e)
public void windowDeactivated(WindowEvent e)
public void windowDeiconified(WindowEvent e)
public void windowIconified(WindowEvent e)
public void windowOpened(WindowEvent e)

Hay que volver a definirlos todos.
Si ponemos en marcha el ejemplo vemos, gracias a las System.out.println colocadas en los métodos redefinidos, a qué tipo de suceso de la ventana están asociados los distintos métodos, como, por ejemplo, windowClosed se invoca cuando se pulsa la X de la ventana.

Como ejercicio intentad escribir unos WindowListener para escuchar el suceso cerrar Ventana para todos los Frame definidos en los ejemplos de este capítulo (los dejé a posta sin definición).

Los menús analizados no son los únicos que se pueden implementar en Java. Otro tipo de menú es el de tipo Popup, es decir, el menú que se asocia a un componente o a una posición. Un ejemplo de menú popup es el que sale en el desktop del sistema operativo Windows cuando se aprieta el botón derecho del ratón (véase Dibujo).




Para crear un menú popup hay que crear un objeto que pertenezca a la clase PopupMenu, utilizando uno de los constructores: PopupMenu(), PopupMenu(String label), que crean, respectivamente, un menú sin o con etiqueta.

PopupMenu es una extensión de Menú, por lo tanto hereda los métodos incluso los que sirven para añadir y eliminar unos MenuItem. En cambio, entre sus métodos hay uno para visualizar el menú en una posición establecida de la pantalla con respecto a un determinado componente: show(Component origin, int x, int y)






Listas y selecciones


A menudo en las interfaces de nuestro Apliques nos sucede que el usuario tiene que hacer una o más selecciones entre varias posibilidades. Para esto tenemos que hacer una lista de las posibilidades y después leer la opción.
Para hacerlo podemos utilizar las listas, que representan una serie de objetos y dan la posibilidad de elegir. Pensemos, por ejemplo, en un aplique que gestiona las reservas de visitas guiadas de algunas localidades y que nos obligue a elegir una.
Además de las form conocidas para el Nombre, Apellidos, etc.. tendremos la lista de las localidades. Analicemos cómo podemos implementarla. Para construir la lista utilizaremos uno de los tres constructores:

List() , crear una nueva lista
List(int rows), crea una nueva lista con rows líneas
List(int rows, boolean multipleMode), crea una nueva lista con rows líneas, y se le dice que, según el valor booleano multipleMode, se podrán elegir uno o más elementos de la lista.

En nuestro caso utilizaremos la tercera forma de constructor.

List lista=new List(0,true);

Algunos métodos que podemos utilizar en las listas son:

void add(String item) e void add(String item, int index), para colgar, al final de la lista o en cierta posición, un nuevo componente.

void addActionListener(ActionListener l), para asociar un ActionListener a la lista.
void addItemListener(ItemListener l), para asociar un ItemListener a la lista.
String getItem(int index), para tener el elemento en posición indicada.
int getItemCount() , para obtener el número de los elementos.
String[] getItems(), para obtener todos los elementos.
EventListener[] getListeners(Class listenerType) , para obtener los oyentes asociados a la lista del tipo que queremos.
Dimension getMinimumSize(), da el tamaño mínimo de la lista.
Dimension getPreferredSize(), da el tamaño preferido para la lista.
int getRows() , dice el número de líneas al momento visibles en la lista.
Int getSelectedIndex(), da el índice del elemento seleccionado.
int[] getSelectedIndexes(), da los índices de los elementos seleccionados.
String getSelectedItem(), da el objeto seleccionado.
String[]getSelectedItems(), da los objetos seleccionados.
Object[] getSelectedObjects(), da la lista de los elementos seleccionados en un vector de objetos.
boolean isIndexSelected(int index), dice si el índice está seleccionado.
boolean isMultipleMode(), dice si, en la lista, se pueden seleccionar más elementos.
void makeVisible(int index), visualiza el item en la posición indicada.
void remove(int position), void remove(String item), elimina los elementos indicados por el índice o la etiqueta.
void removeAll(), elimina todos los elementos de la lista.
void removeActionListener(ActionListener l) e void removeItemListener(ItemListener l), eliminan los oyentes de sucesos definidos para la lista.
void replaceItem(String newValue, int index), modifica el elemento especificado.
void select(int index), selecciona el elemento indicado en la lista.
void setMultipleMode(boolean b), dice a la lista si es posible seleccionar sólo un elemento o más de uno.

Veamos el ejemplo sobre el uso de las listas.

import java.awt.*;
import java.awt.event.*;

public class listas extends Frame
{

List lista=new List(0,true);
Label text=new Label("Maravillas que se pueden visitar en la localidad elegida");

public listas()
{
super("Elegir itinerario");

lista.add("Bienvenido");
lista.add("Foiano de Val Fortore");
lista.add("Baselice");
lista.add("San Bartolomeo en Galdo");
lista.add("San Marco de los Cavoti");
lista.add("Montefalcone en Val Fortore");
lista.add("Pesco Sannita");
lista.add("Colle Sannita");
lista.add("Castelvetere en Val Fortore");
lista.add("Castelfranco en Miscano");
lista.add("Ginestra de los Schiavoni");
lista.add("San Giorgio la Molara");
lista.add("Molinara");
lista.add("Pietrelcina");
lista.add("Fragneto Monforte");
lista.add("Circello");
lista.add("Campolattaro");

add(lista,BorderLayout.CENTER);
add(text,BorderLayout.SOUTH);

addWindowListener(new listeWindowListener());
lista.addItemListener(new escuchaLista());

setSize(350,100);

setResizable(false);

show();

}


public static void main(String [] arg)
{

new listas();

}


class listeWindowListener implements WindowListener
{

public void windowActivated(WindowEvent e)
{}

public void windowClosed(WindowEvent e)
{}

public void windowClosing(WindowEvent e)
{


String[] s=lista.getSelectedItems();
int i=0;
System.out.println("Itinerario seleccionado");
try
{
while (true)
{

System.out.println(s[i++]);

}

}
catch (ArrayIndexOutOfBoundsException er)
{System.out.println("Qué lo pases bien...");}
System.exit(0);
}

public void windowDeactivated(WindowEvent e)
{}

public void windowDeiconified(WindowEvent e)
{}

public void windowIconified(WindowEvent e)
{}

public void windowOpened(WindowEvent e)
{}

}


class escuchaLista implements ItemListener
{

public void itemStateChanged(ItemEvent e)
{

int índice=((Integer) e.getItem()).intValue();

if (índice==0) text.setText("Rocca de los Rettori, arco de Trajano, anfiteatro Romano, ciudad espectáculo");
if (índice==1) text.setText("localidad San Giovanni, Campanario, via Roma, lago, fiesta S.Giovanni, fiesta del emigrante");
if (índice==2) text.setText("óasis ds San Leonardo");
if (indice==3) text.setText("casco histórico");
if (índice==4) text.setText("casco histórico");
if (índice==5) text.setText("casco histórico");
if (índice==6) text.setText("casco histórico");
if (índice==7) text.setText("casco histórico");
if (índice==8) text.setText("casco histórico");
if (índice==9) text.setText("Bosque");
if (índice==10) text.setText("casco histórico");
if (índice==11) text.setText("Lago de San Giorgio");
if (índice==12) text.setText("casco histórico");
if (índice==13) text.setText("Piana Romana, casco histórico, casas de Padre Pío");
if (índice==14) text.setText("Encuentro internacional de globos, Palacio Ducal");
if (índice==15) text.setText("casco histórico");
if (índice==16) text.setText("Dique de Campolattaro");

}

}

}

Por lo tanto, las listas son unos buenos GUI para que el usuario ponga en marcha una opción entre las muchas posibilidades.
Hay otro GUI que sirve para esto, que prácticamente es una lista que aparece y desaparece, en el sentido de que se puede ver sólo el objeto seleccionado y que los demás se ven sólo cuando hay que hacer la selección, tipo menú, mientras en las listas se pueden ver siempre.
El GUI del que estoy hablando es el Choice (selección), cuyo funcionamiento es parecido al de las listas.
El constructor es uno sin parámetros, mientras los métodos son:

void add(String item), añade una posibilidad al final de las selecciones posibles.
void addItem(String item), como la add
void addItemListener(ItemListener l), asocia un oyente de sucesos para la Choice.
String getItem(int index), devuelve la elección posible que se encuentra en el índice .
int getItemCount(), da el número de posibilidades para la Choice.
EventListener[] getListeners(Class listenerType), da todos los oyentes asociados a la Choice.
int getSelectedIndex(), devuelve el índice de la lista seleccionada en la Choice.
String getSelectedItem(), devuelve la opción seleccionada en la Choice.
Object[] getSelectedObjects(), da todos los item seleccionados.
void insert(String item, int index), introduce una seleccióm en la posición indicada de la Choice.

void remove(int position), void remove(String item), void removeAll() , para eliminar las selecciones posibles de la lista.

void removeItemListener(ItemListener l), elimina el oyente de sucesos de tipo ItemListener asociado a la Choice.

void select(int pos), void select(String str), para seleccionar una opción.

Escribamos un pequeño programa que utilice las Choice. Pero, como hasta ahora hemos creado unas aplicaciones a ventana, creemos un aplique, y visto que es GUI, se pueden utilizar en los dos tipos de programas.
Hablando de aplique, como no lo hemos hacho hasta ahora, creemos un aplique que lee los parámetros que le pasan los archivos html que lo invoca. Es lo que hacen prácticamente la mayor parte de los apliques del sito HTMLpoint.
En el aplique, como ejemplo, he puesto un pequeño control sobre el campo autor. Esto me sirve para enseñaros cómo se puede hacer. Puede resultar útil si se crea un aplique y lo distribuimos de forma que sea obligatorio el parámetro del autor y su valor. También sirve para evitar que otros puedan hacerse creadores del aplique y, por lo tanto, pretender los derechos de la creación del aplique.

El control no es complicado, un hacker lo evitaría fácilmente. Sin embargo un hacker no tiene ningún interés en destruir un programa free, sólo para eliminar los derechos de autor. En cambio, para un usuario normal es imposible poner en marcha el programa sin especificar el nombre del autor. El nombre puede incluso ser un número de serie si queremos vender un programa.

El archivo html, se llamará Choice.html, y su contenido es:

<html>
<head>
<title>
Ejemplo de uso de la java.awt.Choice y del cambio de los parámetros a un aplique
</title>
</head>
<body>
<APPLET code="Selecciones.class" width=350 height=100>
<param name=loc1 value="Bienvenido">
<param name=loc2 value="Foiano de Val Fortore">
<param name=loc3 value="Baselice">
<param name=loc4 value="San Bartolomeo en Galdo">
<param name=loc5 value="San Marco de los Cavoti">
<param name=loc6 value="Montefalcone in Val Fortore">
<param name=loc7 value="Pesco Sannita">
<param name=loc8 value="Colle Sannita">
<param name=loc9 value="Castelvetere en Val Fortore">
<param name=loc10 value="Castelfranco en Miscano">
<param name=loc11 value="Ginestra de los Schiavoni">
<param name=loc12 value="San Giorgio la Molara">
<param name=loc13 value="Molinara">
<param name=loc14 value="Fragneto Monforte">
<param name=loc15 value="Circello">
<param name=loc16 value="Campolattaro">
<param name=autore value="Pietro Castellucci">

</APPLET>
</body>
</html>

Mientras que el código del aplique, editado en el archivo llamado Selecciones.java, es:

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class Selecciones extends Applet
{


Label text=new Label("Maravillas que se pueden visitar en la localidad seleccionada");
Choice scelte=new Choice();
public void init()
{

// Control de los derechos de autor:
String autor=getParameter("autor");
if (autor==null) System.exit(0);
if (autor.compareTo("Pietro Castellucci")!=0)
{
System.out.println("Parámetro autor no valido, introducir como valor Pietro Castellucci");
System.exit(0);
}


String p=getParameter("loc1");
if (p==null) p="Localidad 1 no definida";
scelte.add(p);

p=getParameter("loc2");
if (p==null) p="Localidad 2 no definida";
scelte.add(p);

p=getParameter("loc3");
if (p==null) p="Localidad 3 no definida";
scelte.add(p);

scelte.add(p);

p=getParameter("loc4");
if (p==null) p="Localidad 4 no definida";
scelte.add(p);

p=getParameter("loc5");
if (p==null) p="Localidad 5 no definida";
scelte.add(p);

p=getParameter("loc6");
if (p==null) p="Localidad 6 no definida";
scelte.add(p);

p=getParameter("loc7");
if (p==null) p="Localidad 7 no definida";
scelte.add(p);

p=getParameter("loc8");
if (p==null) p="Localidad 8 no definida";
scelte.add(p);

p=getParameter("loc9");
if (p==null) p="Localidad 9 no definida";
scelte.add(p);

p=getParameter("loc10");
if (p==null) p="Localidad 10 no definida";
scelte.add(p);

p=getParameter("loc11");
if (p==null) p="Localidad 11 no definida";
scelte.add(p);

p=getParameter("loc12");
if (p==null) p="Localidad 12 no definida";
scelte.add(p);

p=getParameter("loc13");
if (p==null) p="Localidad 13 no definida";
scelte.add(p);

p=getParameter("loc14");
if (p==null) p="Localidad 14 no definida";
scelte.add(p);

p=getParameter("loc15");
if (p==null) p="Localidad 15 no definida";
scelte.add(p);

p=getParameter("loc16");
if (p==null) p="Localidad 16 no definida";
scelte.add(p);

p=getParameter("loc17");
if (p==null) p="Localidad 17 no definida";
scelte.add(p);

scelte.addItemListener(new escuchaChoice());


// Visualizzo la Choice

add(selecciones, BorderLayout.CENTER);
add(text, BorderLayout.SOUTH);

}

class escuchaChoice implements ItemListener
{

public void itemStateChanged(ItemEvent e)
{

int indice=scelte.getSelectedIndex();

if (indice==0) text.setText("Rocca dei Rettori, arco de Trajano, anfiteatro Romano");
if (indice==1) text.setText("localidad San Giovanni, Campanario, via Roma, lago");
if (índice==2) text.setText("óasi de San Leonardo");
if (índice==3) text.setText("casco histórico");
if (índice==4) text.setText("casco histórico");
if (índice==5) text.setText("");
if (índice==6) text.setText("");
if (índice==7) text.setText("");
if (índice==8) text.setText("");
if (índice==9) text.setText("Bosque");
if (índice==10) text.setText("");
if (índice==11) text.setText("Lago de San Giorgio");
if (índice==12) text.setText("");
if (índice==13) text.setText("Piana Romana, casco histórico, casas de Padre Pío");
if (índice==14) text.setText("Encuentro internacional de globos, palcio Ducale");
if (índice==15) text.setText("");
if (índice==16) text.setText("Dique de Campolattaro");
}
}
}

El último componente GUI que veremos en esta lección es el ScrollPane, es decir, un panel en el que es posible introducir un componente tan grande como queramos, y que tiene que ser visualizado a trozos.
El ScrollPane usa dos Scrollbar, una horizontal y otra vertical, para seleccionar la parte del GUI que queremos ver. Fijaos que la Scrollbar es un objeto también, por lo tanto, se puede introducir y gestionar en las proprias aplicaciones. En el ScrollPane se puede elegir si visualizar las Scrollbar siempre, nunca o sólo cuando sea necesario.
Un ScrollPane típico es el que utilizamos para visualizar un archivo de texto.
Hay dos tipos de constructores para el objeto:

ScrollPane(int sbp), crea un ScrollPane que pueda visualizar las Scrollbar definidas por spb.

Los valores posibles son :
ScrollPane.SCROLLBARS_ALWAYS siempre a la vista
ScrollPane.SCROLLBARS_AS_NEEDED a la vista sólo si lo necesitamos
ScrollPane.SCROLLBARS_NEVER nunca a la vista

ScrollPane(), crea un ScrollPane que pueda visualizar ScrollPane.SCROLLBARS_AS_NEEDED.

Entre los métodos, además de los que sirven para gestionar el ScrollPane, encontramos los de Container y de Component. En efecto, ScrollPane es una extensión de Container, por lo tanto, si lo vemos como un contenedor, se puede ver como un componente.





El Texto, los sucesos, Dialog


Nos queda por ver un componente fundamental para una interfaz, es decir, el texto.
Los abstract window Toolkit de Java ponen a disposición dos clases para el texto: TextArea y TextField, las dos amplían la clase TextComponent.



En TextComponent encontramos una serie de métodos útiles para la gestión del texto, tanto en TextArea como en TextField, entre ellos:

Color getBackground() e setBackground(Color c), para capturar y verificar el color de Background del texto.
String getSelectedText(), captura el texto seleccionado.
int getSelectionEnd(), da la posición del final de la selección del texto.
Int getSelectionStart(), da la posición del inicio de la selección del texto.
String getText(), da el texto del TextComponent
boolean isEditable(), dice si el texto del componente se puede editar.
void select(int selectionStart, int selectionEnd), selecciona el texto de selectionStart a selectionEnd.
void selectAll(), selecciona todo el texto.
void setEditable(boolean b), verifica si el texto se puede editar o no.
void setSelectionEnd(int selectionEnd), verifica el final de la selección del texto.
void setSelectionStart(int selectionStart), verifica el inicio de la selección.
void setText(String t), verifica el contenido del componente del texto con valor t.

Además en TextComponent se pueden utilizar todos los métodos de Component, es decir:

action, add, addComponentListener, addFocusListener, addHierarchyBoundsListener, addHierarchyListener, addInputMethodListener, addKeyListener, addMouseListener, addMouseMotionListener, addNotify, addPropertyChangeListener, addPropertyChangeListener, bounds, checkImage, checkImage, coalesceEvents, contains, contains, createImage, createImage, deliverEvent, disable, disableEvents, dispatchEvent, doLayout, enable, enable, enableEvents, enableInputMethods, firePropertyChange, getAlignmentX, getAlignmentY, getBounds, getBounds, getColorModel, getComponentAt, getComponentAt, getComponentOrientation, getCursor, getDropTarget, getFont, getFontMetrics, getForeground, getGraphics, getGraphicsConfiguration, getHeight, getInputContext, getInputMethodRequests, getLocale, getLocation, getLocation, getLocationOnScreen, getMaximumSize, getMinimumSize, getName, getParent, getPeer, getPreferredSize, getSize, getSize, getToolkit, getTreeLock, getWidth, getX, getY, gotFocus, handleEvent, hasFocus, hide, imageUpdate, inside, invalidate, isDisplayable, isDoubleBuffered, isEnabled, isFocusTraversable, isLightweight, isOpaque, isShowing, isValid, isVisible, keyDown, keyUp, layout, list, list, list, list, list, locate, location, lostFocus, minimumSize, mouseDown, mouseDrag, mouseEnter, mouseExit, mouseMove, mouseUp, move, nextFocus, paint, paintAll, postEvent, preferredSize, prepareImage, prepareImage, print, printAll, processComponentEvent, processFocusEvent, processHierarchyBoundsEvent, processHierarchyEvent, processInputMethodEvent, processKeyEvent, processMouseEvent, processMouseMotionEvent, remove, removeComponentListener, removeFocusListener, removeHierarchyBoundsListener, removeHierarchyListener, removeInputMethodListener, removeKeyListener, removeMouseListener, removeMouseMotionListener, removePropertyChangeListener, removePropertyChangeListener, repaint, repaint, repaint, repaint, requestFocus, reshape, resize, resize, setBounds, setBounds, setComponentOrientation, setCursor, setDropTarget, setEnabled, setFont, setForeground, setLocale, setLocation, setLocation, setName, setSize, setSize, setVisible, show, show, size, toString, transferFocus, update, validate

Ahora, veamos los TextField. Prácticamente un TextField es una única línea de texto que se puede editar, con aspecto gráfico. Es uno de los campos que estamos acostumbrados a ver en las Form que se encuentran en internet para introducir nombres, apellidos, etc.

Hay cuatro posibles constructores:

TextField(), crea un TextField vacío.
TextField(int c), crea un TextField vacío de c columnas, es decir, una línea de c caracteres.
TextField(String t), crea un TextField inicializado con t.
TextField(String t, int c), crea un TextField inicializado con t, de c caracteres.

De los varios métodos, los más interesantes para nuestros fines son:

boolean echoCharIsSet(), dice si el TextField realiza el "echo" de los caracteres introducidos.
int getColumns(), da el número de columnas de los TextField.
char getEchoChar(), da el carácter utilizado para el "echo".
void setColumns(int columns), verifica el número de las columnas de los TextField.
void setEchoChar(char c), verifica el carácter de "echo" para el TextField.
void setText(String t), para verificar el texto introducido.

Para el tamaño:

Dimension getMinimumSize()
Dimensión getMinimumSize(int c)
Dimensión getPreferredSize()
Dimensión getPreferredSize(int c)

La TextArea, en cambio, es un verdadero texto, no sólo una línea, sino muchas. Incluye también las dos barras para navegar en el texto si éste es más grande de la ventana en la que está visualizado.

Los constructores son:

TextArea(), construye una nueva TextArea.
TextArea(int r, int c) , construye una nueva TextArea, de r líneas y c columnas.
TextArea(String text), construye una nueva TextArea inicializada con el texto pasado.
TextArea(String text, int rows, int columns) , construye una nueva TextArea inicializada con el texto pasado, de r líneas y c columnas.
TextArea(String text, int rows, int columns, int scrollbars), como el anterior, sólo que permite especificar la visualización de las barras de texto.

Vamos a ver algunos métodos:

void append(String str), cuelga el texto pasado a la TextArea. (En la viejas versiones de Java es appendText(String str)).
int getColumns(), int getRows() para tener información sobre el número de columnas o líneas.
void insert(String str, int pos), introduce el texto pasado en la posición pasada. (En las viejas versiones de Java es insertText(String str)).
void replaceRange(String str, int start, int end), sustituye el texto de start a end con la cadena pasada.
void setColumns(int columns) e void setRows(int rows) para verificar el número de columnas o de líneas de la TextArea.

Para el tamaño del objeto GUI:

Dimensión getMinimumSize()
Dimensión getMinimumSize(int rows, int columns)
Dimensión getPreferredSize()
Dimensión getPreferredSize(int rows, int columns)

Hemos visto todos los componentes de texto. Llegados a este punto podemos poner un ejemplo que los utiliza las dos.

Creamos un aplique, por lo tanto el launcher es:

<html>
<head>
<title>
Ejemplo de uso de los componentes de texto.
</title>
</head>
<body>
<APPLET code="Texto.class" width=500 height=200>
<param name=testo value="Texto inicial para la TextArea.Introducir más caracteres.">
</APPLET>
</body>
</html>

El código que hay que editar en Texto.java, es el siguiente:

import java.awt.event.KeyListener;

import java.awt.event.KeyEvent;

import java.awt.TextField;

import java.awt.TextArea;

import java.awt.BorderLayout;

import java.applet.*;


public class Texto extends Applet
{

TextField TF=new TextField(20);

TextArea TA=new TextArea();

public void init()
{

add(TA,BorderLayout.CENTER);

add(TF,BorderLayout.SOUTH);

String t=getParameter("texto");

if (t!=null) TA.setText(t);

TF.setEditable(false);

TA.addKeyListener(new MyKeyListener());

}


public class MyKeyListener implements KeyListener
{
public void keyPressed(KeyEvent e)
{

}

public void keyReleased(KeyEvent e)
{

int valor=e.getKeyCode();
if (valor!=10) TF.setText("Introducido carácter "+e.getKeyChar());
else TF.setText("Introducido carácter ENVIAR");

}

public void keyTyped(KeyEvent e)
{

}

}

}




La gestión de los sucesos en Java2


 
Hemos visto casi todos los componentes GUI de awt. Para construir una interfaz basta con combinarlos y escuchar los sucesos.
Por cada GUI analizada, hemos visto cómo gestionar unos sucesos. Ahora vamos a ver qué sucesos se pueden escuchar.
En primer lugar hemos escuchado unos sucesos de tipo ActionEvent, es decir, sucesos que actúan sobre las GUI gracias al usuario como, por ejemplo, pulsar un botón.
Para esto, os recuerdo que hemos implementado la interfaz ActionListener, y hemos vuelto a definir el único suceso actionPerformed (ActionEvent e), que se invoca cuando se pone en marcha una acción sobre el componente GUI (o sobre los componentes) a los que está asociado.
Para asociar al GUI el oyente de los sucesos que hemos definido, hemos utilizado el método addActionListener (ActionListener oyente) del GUI.
Para usarlos hay que incluir en el programa:

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

o

impore java.awt.event.*;

Oyentes de sucesos de tipo ActionListener se pueden asociar a los objetos GUI de awt:

Button
List (cuando seleccionamos o no seleccionamos un elemento)
MenuItem
TextField

Hemos visto también cómo implementar un ItemListener, para escuchar sucesos de la GUI que tienen un estado de on/off, cuando modifican su propiio estado.
Para asociarlo a una GUI hemos utilizado addItemListener(ItemListener oyente) de la GUI. Cuando el suceso es generado por GUI, se invoca el método itemStateChanged(ItemEvent e) del oyente asociado.

Hay que incluir:

import java.awt.event.*;

o

import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;

Los GUI awt para que pueda ser escuchado, son:

Checkbox
CheckboxMenuItem (no lo hemos visto. Es como un MenuItem, lo único es que funciona como una Checkbox, es decir, se puede clicar o no. Si se asocia a un CheckboxGroup, se convierte otra vez en un radiobutton, sólo que en un menú).
Choice
List

Además hemos visto los oyentes de los sucesos de las ventanas, es decir, los de tipo WindowListener.
Se asocian a las ventanas usando el método de éstas addWindowListener(WindowListener WL), y para definirlas hay que implementar la interfaz WindowListener y volver a definir los métodos:

void windowActivated(WindowEvent e), invocado cuando la ventana está activa, es decir, cuando aparece en primer plano en el desktop.
void windowClosed(WindowEvent e), invocado cuando la ventana se cierra.
void windowClosing(WindowEvent e), invocado cuando se aprieta el botón cerrarVentana (X).
void windowDeactivated(WindowEvent e), invocado cuando la ventana pasa a un segundo plano.
void windowDeiconified(WindowEvent e), invocado cuando la ventana se convierte de icono a activa.
void windowIconified(WindowEvent e), cuando se transforma en icono.
void windowOpened(WindowEvent e), cuando se abre.

Para escuchar los sucesos de la ventana hay que incluir:

import java.awt.event.WindowListener;
import java.awt.event.WindowEvent;

o

import java.awt.event.*;

Los sucesos de las ventanas se manifiestan casi siempre por parejas. Por ejemplo, cuando pulsamos la tecla X en la parte de arriba a la derecha de la ventana, primero se invoca windowClosing y después windowClosed, o cuando una ventana se transforma de icono a activa, primero escucha windowDeiconified y luego WindowActivated, etc.

Es posible escuchar sucesos de tipo ventana para los elementos:

Window
Frame
Dialog

Por lo que se refiere a los Dialog abro un paréntesis.
Son Frame sin icono. Reducir a icono y maximizar son muy parecidos para hacer precisamente unos diálogos rápidos con el usuario. Son, por ejemplo, unos dialog las ventanas que aparecen en las aplicaciones y dicen: ¿estás seguro de que quieres salir?
Un Dialog puede ser modal o no modal. El primero es un Dialog que bloquea completamente la aplicación y que, por tanto, ya no oye los sucesos, el segundo en cambio va en paralelo a ésta.
Los dialog de awt no pueden incluir menús, mientras que sí los incluyen los de swing (javax.swing.JDialog) si.

Vamos a ver qué sucesos pueden escuchar los objetos de tipo TextComponent, es decir, objetos de tipo TextField y TextArea. Podemos escuchar sucesos de tipo TextEvent, implementando la interfaz TextListener, y volviendo a definir el método textValueChanged(TextEvent e), invocado cada vez que el texto se modifica.
La interfaz y el suceso se encuentran en java.awt.event

Los objetos de tipo container, es decir, Panel, ScrollPane, Window (y, por lo tanto, Dialog y Frame), pueden escuchar los sucesos en el contenedor, utilizando el método addContainerListener(ContainerListener l). Hay que implementar la interfaz ContainerListener y volver a definir los métodos.

void componentAdded(ContainerEvent e)
void componentRemoved(ContainerEvent e)

Éstos se invocan automáticamente cuando se añaden o se quitan elementos al contenedor.
Hay que incluir java.awt.event.ContainerListener y java.awt.event.ContainerEvent.

Llegados a este punto vamos a ver qué sucesos se pueden escuchar en objetos de tipo Component, es decir, en TODOS los componentes awt, incluidos los contenedores y las ventanas.

En Component están los métodos:

addComponentListener(ComponentListener l)
addFocusListener(FocusListener l)
addHierarchyBoundsListener(HierarchyBoundsListener l)
addHierarchyListener(HierarchyListener l)
addInputMethodListener(InputMethodListener l)
addKeyListener(KeyListener l)
addMouseListener(MouseListener l)
addMouseMotionListener(MouseMotionListener l)
addPropertyChangeListener(PropertyChangeListener listener)
addPropertyChangeListener(String propertyName, PropertyChangeListener listener)

Los ComponentListener escuchan sucesos en el componente y hay que volver a definir los métodos.

void componentHidden(ComponentEvent e)
void componentMoved(ComponentEvent e)
void componentResized(ComponentEvent e)
void componentShown(ComponentEvent e)

Éstos se invocan cuando el componente se oculta, se mueve, cambia su tamaño y se visualiza.

FocusListener escucha los sucesos de focus del teclado en el componente, es decir, si se selecciona o no el componente del teclado.
Hay que volver a definir los métodos:

focusGained(FocusEvent e), invocado cuando se selecciona el componente.
focusLost(FocusEvent e), invocado por el componente cuando pierde la selección del teclado.

Pensemos, por ejemplo, en la navegación de las varias form de una interfaz, pulsando la tecla TAB.

HierarchyBoundsListener, escucha los sucesos de remoción de los antepasados del componente, por ejemplo, un botón en una ventana. Se implementa esta interfaz, escucha si la ventana se mueve.
Hay que volver a definir los métodos:

void ancestorMoved(HierarchyEvent e), invocada cuando el antepasado se remueve.
void ancestorResized(HierarchyEvent e) , invocada cuando se cambia de tamaño el antepasado.

HierarchyListener escucha los cambios de los antepasados del componente. Hay que volver a definir el método hierarchyChanged(HierarchyEvent e). Será HierarchyEvent el que incluye el cambio.

KeyListener ya lo hemos visto: escucha los sucesos del teclado. Hay que volver a definir los métodos.
void keyPressed(KeyEvent e), invocado cuando se tecla una tecla.
void keyReleased(KeyEvent e), invocado cuando se deja de teclear una tecla.
void keyTyped(KeyEvent e), invocado cuando se sigue pulsando una tecla.
En resumen, cuando se teclea una tecla se oyen los sucesos en éste orden: keyPressed, keyTyped y keyReleased.

MouseListener escucha los sucesos del ratón. Hay que volver a definir los métodos.
void mouseClicked(MouseEvent e), invocado cundo se clica un botón del ratón en el componente.
void mouseEntered(MouseEvent e), invocado cuando el ratón entra sobre el componente.
void mouseExited(MouseEvent e), invocado cuando el ratón sale del componente.
void mousePressed(MouseEvent e), invocado cuando se sigue teniendo pulsado el ratón sobre el componente.
void mouseReleased(MouseEvent e), invocado cuando se deja de pulsar el ratón.

MouseMotionListener, otros sucesos del ratón sobre el componente:
mouseDragged(MouseEvent e), invocado cuando se aprieta y se mueve el ratón sobre el componente.
void mouseMoved(MouseEvent e), invocado cuando el ratón se mueve sobre el componente, con o sin pulsar botones.

La última interfaz para los sucesos del ratón es MouseInputListener, que implementa las dos interfaces anteriores. Por lo tanto escucha todos los sucesos anteriores del ratón.

En el ejemplo a continuación se escuchan varios sucesos y se utiliza también un Dialog.

import java.awt.event.*;
import java.awt.*;

class escuchar extends Frame
{

Button b1=new Button("Botón1");

Button b2=new Button("Visualiza Dialog");

Button b3=new Button("salir");

Button b4=new Button("Cerrar Dialog");

Choice l1=new Choice();

TextField TF1=new TextField(15);

Dialog D;

AscoltaActionListener aal;
AscoltaItemListener ail;
AscoltaWindowListener awl;
AscoltaWindowListenerDialog awld;
AscoltaMouseListener aml;
AscoltaKeyListener akl;
public Ascolta()
{
setTitle("Frame, ejemplo oyentes suscesos");

setLocation(100,100);

setLayout(new GridLayout(5,1));
add(b1);
add(b2);
add(b3);
add(l1);
add(TF1);

D=new Dialog(this,true);
D.setSize(200,100);
D.setLocation(200,100);
D.add(b4,BorderLayout.SOUTH);
D.setTitle("Dialog - modale");
preparaD(false);

l1.add("Selección 1");
l1.add("Seleccióón 2");
l1.add("Selección 3");

// Inicializar los oyentes de los sucesos.
aal=new AscoltaActionListener();
ail=new AscoltaItemListener();
awl=new AscoltaWindowListener();
awld=new AscoltaWindowListenerDialog();
aml=new AscoltaMouseListener();
akl=new AscoltaKeyListener();
b1.addActionListener(aal);
b2.addActionListener(aal);
b3.addActionListener(aal);
TF1.addActionListener(aal);
l1.addItemListener(ail);
addWindowListener(awl);
addMouseListener(aml);
b1.addMouseListener(aml);
b2.addMouseListener(aml);
b3.addMouseListener(aml);
b4.addMouseListener(aml);
l1.addMouseListener(aml);
TF1.addMouseListener(aml);
TF1.addTextListener(new TextListener()
{
public void textValueChanged(TextEvent e)
{
System.out.println("TextListener: cambiar el valor de la TextField");
}
}
);
D.addMouseListener(aml);
addKeyListener(akl);
b1.addKeyListener(akl);
b2.addKeyListener(akl);
b3.addKeyListener(akl);
b4.addKeyListener(akl);
l1.addKeyListener(akl);
TF1.addKeyListener(akl);
D.addKeyListener(akl);
pack();
show();
}

void prepararD(boolean m)
{
D.setModal(m);
}

public static void main (String [] s)
{
System.out.println("Escuchar los sucesos.");
new Escuchar();

}

// ActionListener

class EscucharActionListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{

String c=e.getActionCommand();
if (c.compareTo("Botón1")==0) System.out.println("ActionListener: Pulsar Botón1");
else
if (c.compareTo("Salir")==0)
{
System.out.println("ActionListener: Pulsar Salir");
System.exit(9); // es un número cualquiera, se llama exit code.
} else
if (c.compareTo("Visualizar Dialog")==0)
{
System.out.println("ActionListener: Pulsar Visualizar Dialog");
D.show();
b4.addActionListener(aal);
b2.removeActionListener(aal);
D.addWindowListener(awld);
} else
if (c.compareTo("Cerrar Dialog")==0)
{
System.out.println("ActionListener: Pulsar Visualizar Dialog");
D.hide();
b4.removeActionListener(aal);
b2.addActionListener(aal);
D.removeWindowListener(awld);
} else
{
System.out.println("ActionListener: Pulsar Enviar en la TextField, letto:"+TF1.getText());
TF1.setText("");
}

}
}

// ItemListener
class EscucharItemListener implements ItemListener
{

public void itemStateChanged(ItemEvent e)
{
String val=l1.getSelectedItem();
System.out.println("ItemListener: Seleccionado "+val);
}

}

// WindowListener

public class EscucharWindowListener implements WindowListener
{
public void windowActivated(WindowEvent e)
{
System.out.println("WindowListener: Ventana activada");
}

public void windowClosed(WindowEvent e)
{
System.out.println("WindowListener: Ventana cerrada");
}

public void windowClosing(WindowEvent e)
{
System.out.println("WindowListener: Pulsar cerrar ventana");
System.exit(0);
}

public void windowDeactivated(WindowEvent e)
{
System.out.println("WindowListener: Ventana no activada");
}

public void windowDeiconified(WindowEvent e)
{
System.out.println("WindowListener: Ventana sin icono");
}

public void windowIconified(WindowEvent e)
{
System.out.println("WindowListener: Ventana reducir a icono");
}

public void windowOpened(WindowEvent e)
{
System.out.println("WindowListener: Ventana abierta");
}
}


public class EscucharWindowListenerDialog implements WindowListener
{
public void windowActivated(WindowEvent e)
{
System.out.println("WindowListener: Dialog activado");
}

public void windowClosed(WindowEvent e)
{
System.out.println("WindowListener: Dialog cerrado");
}

public void windowClosing(WindowEvent e)
{
System.out.println("WindowListener: Pulsar cerrar Dialog");
D.hide();
b4.removeActionListener(aal);
b2.addActionListener(aal);
D.removeWindowListener(awld);
}

public void windowDeactivated(WindowEvent e)
{
System.out.println("WindowListener: Ventana no activada");
}

public void windowDeiconified(WindowEvent e)
{
System.out.println("WindowListener: Dialog sin icono");
}

public void windowIconified(WindowEvent e)
{
System.out.println("WindowListener: Dialog reducir a icono");
}

public void windowOpened(WindowEvent e)
{
System.out.println("WindowListener: Dialog abierto");
}
}

// Mouse Listener:
class EscucharMouseListener implements MouseListener
{

public void mouseClicked(MouseEvent e)
{
Component a=e.getComponent();
String n=a.getName();
System.out.println("MouseListener: Mouse clicado sobre el componente "+n);
}
public void mouseEntered(MouseEvent e)
{
Component a=e.getComponent();
String n=a.getName();
System.out.println("MouseListener: Mouse entrado en el componente "+n);
}
public void mouseExited(MouseEvent e)
{
Component a=e.getComponent();
String n=a.getName();
System.out.println("MouseListener: Mouse salido del componente "+n);
}
public void mousePressed(MouseEvent e)
{
Component a=e.getComponent();
String n=a.getName();
System.out.println("MouseListener: el botón está pulsado sobre el componente"+n);
}
public void mouseReleased(MouseEvent e)
{
Component a=e.getComponent();
String n=a.getName();
System.out.println("MouseListener: Mouse no está pulsado en el componente "+n);
}
}

// Teclado
class AscoltaKeyListener implements KeyListener
{
public void keyPressed(KeyEvent e)
{
System.out.println("KeyListener: Pulsar tecla "+e.getKeyChar()+
" codice "+
e.getKeyCode());
}
public void keyReleased(KeyEvent e)
{
System.out.println("KeyListener: Dejar de pulsar tecla "+e.getKeyChar()+
" codice "+
e.getKeyCode());
}
public void keyTyped(KeyEvent e)
{
System.out.println("KeyListener: Estás pulsando la tecla "+e.getKeyChar()+
" codice "+
e.getKeyCode());
}
}
}




Introducción a swing


Además del paquete java.awt, Java pone a disposición del programador el paquete javax.swing para crear unas interfaces gráficas. En este capítulo veremos para qué la Sun Microsystem ha creado otro paquete y qué diferencias hay con awt.
Para presentar el paquete hablaré del programa que estoy preparando para mi tesina en la Facultad de Informática de la Universidad de Pisa. Para informaciones con respecto a Orespics podéis poneros en contacto conmigo o con las profesoras Laganà y Ricci del Departamento de Informática de Pisa (Corso Italia, 40).
El nombre del programa es Orespics Programming Language y, en práctica, es un ambiente integrado en el que es posible programar agentes paralelos que comunicam entre ellos, intercambiando mensajes. El ambiente permite definir y poner en marcha estos agentes. Se propone como instrumento de soporte didáctico al aprendizaje de las modalidades de programación paralela, programación que puede resultar muy difícil.
Precisamente por ser un instrumento didáctico, tiene una interfaz usuario User Friendly. La interfaz ha sido escrita utilizando el paquete Swing de Java.
Swing ha sido totalmente escrito en Java utilizando el paquete awt, y pone a disposición del usuario muchas clases que están también en awt, pero mucho mejores y más potentes. Además introduce muchas más clases que no están en awt.
Por lo tanto, veamos cuáles son las clases y las interfaces incluidas en el paquete:

Interfaces
Action
BoundedRangeModel
ButtonModel
CellEditor
ComboBoxEditor
ComboBoxModel
DesktopManager
Icon
JComboBox.KeySelectionManager
ListCellRenderer
ListModel
ListSelectionModel
MenuElement
MutableComboBoxModel
Renderer
RootPaneContainer
Scrollable
ScrollPaneConstants
SingleSelectionModel
SwingConstants
UIDefaults.ActiveValue
UIDefaults.LazyValue
WindowConstants

Clases
AbstractAction
AbstractButton
AbstractCellEditor
AbstractListModel
ActionMap
BorderFactory
Box
Box.Filler
BoxLayout
ButtonGroup
CellRendererPane
ComponentInputMap
DebugGraphics
DefaultBoundedRangeModel
DefaultButtonModel
DefaultCellEditor
DefaultComboBoxModel
DefaultDesktopManager
DefaultFocusManager
DefaultListCellRenderer
DefaultListCellRenderer.UIResource
DefaultListModel
DefaultListSelectionModel
DefaultSingleSelectionModel
FocusManager
GrayFilter
ImageIcon
InputMap
InputVerifier
JApplet
JButton
JCheckBox
JCheckBoxMenuItem
JColorChooser
JComboBox
JComponent
JDesktopPane
JDialog
JEditorPane
JFileChooser
JFrame
JInternalFrame
JInternalFrame.JDesktopIcon
JLabel
JLayeredPane
JList
JMenu
JMenuBar
JMenuItem
JOptionPane
JPanel
JPasswordField
JPopupMenu
JPopupMenu.Separator
JProgressBar
JRadioButton
JRadioButtonMenuItem
JRootPane
JScrollBar
JScrollPane
JSeparator
JSlider
JSplitPane
JTabbedPane
JTable
JTextArea
JTextField
JTextPane
JToggleButton
JToggleButton.ToggleButtonModel
JToolBar
JToolBar.Separator
JToolTip
JTree
JTree.DynamicUtilTreeNode
JTree.EmptySelectionModel
JViewport
JWindow
KeyStroke
LookAndFeel
MenuSelectionManager
OverlayLayout
ProgressMonitor
ProgressMonitorInputStream
RepaintManager
ScrollPaneLayout
ScrollPaneLayout.UIResource
SizeRequirements
SizeSequence
SwingUtilities
Timer
ToolTipManager
UIDefaults
UIDefaults.LazyInputMap
UIDefaults.ProxyLazyValue
UIManager
UIManager.LookAndFeelInfo
ViewportLayout

Excepciones
UnsupportedLookAndFeelException

Está claro que hay muchas más clases de las de swing. Además hay muchas que tienen el mismo nombre de algunas clases de awt, excepto una J inicial, como, por ejemplo, JFrame, JDialog, etc. Estas clases funcionan igual que las de awt, pero contienen muchos métodos más útiles.
Presentamos algunas de estás cosas que están en swing más que en awt.
En swing están las Toolbar, es decir, unas pequeñas barras sobre las que hay unos botones. Se pueden mover dentro de las ventanas que las incluyen.
Los botones de swing, como casi todos los demás JComponent, pueden tener tanto una etiqueta como una imagen, imagen que puede cambiar según el estado del botón.
Además en swing se pueden utilizar los Tooltip, es decir, aquellas sugerenias que salen automáticamente en un componente cuando el ratón se detiene en él durante un rato.
Vamos a ver ahora el efecto de estos componentes swing en Orespics.



En el Dibujo podemos notar la Toolbar (en la que he ocultado los bordes) de otras 8 Toolbar, una por cada categoría de botones. Se ven los botones que incluyen las imágenes, unas activas y otras no.



En el Dibujo se puede ver un Tooltip en uno de los botones.



Además podemos notar que incluso en los menús se pueden introducir unas imágenes y esto las convierte en imágenes muy agradables para el usuario.



Las toolbar se pueden ocultar fácilmente y se pueden visualizar en la pantalla.



En el dibijo notamos el cambio de la imagen del botón con el pingüino, que se hace más grande con swing. Como ya hemos dicho, es posible cambiar el icono según el estado del botón.

Otros dos componentes muy interesantes de Swing son los TabbedPane y los Árboles.
Los primeros son los controles a tarjetas típicos de las interfaces de Windows, muy agradables. Los segundos muestran las estructuras a árbol como las que se ven cuando se navega en los discos duros utilizando explorer de Windows.

Con swing se puede incluso cambiar el llamado Look and Feel de la ventana, es decir, su aspecto, convirtiéndola en algo parecido a una interfaz típica de Java, de Windows, de Macintosh (si está en un aparato Mac) y de Linux (X-Windows - Motif).












Con Swing cambia completamente la gestión del texto. Se pueden crear texto de colores, con distintos tipos de caracteres.

Muchas más son las posibilidades de Swing, por ejemplo, unos Dialog para navegar en los archivos con unas preview y unos dialog para elegir los colores. Estas opciones ya vienen implementadas en el paquete.

A mí me resulta muy interesante saber que el dialog de selección de los colores del Dibujo 16 se crea y se utiliza con una sola orden, es decir, que basta con invocar el método:

static JDialog
createDialog(Component c, String title,
boolean modal, JColorChooser chooserPane,
ActionListener okListener,
ActionListener cancelListener)

de la clase JColorChooser.

De todas formas creo que os han quedado claras las potencialidades del paquete que, sin embargo, todavía no está incluido en las versiones de Java de los navegadores y que, por lo tanto, todavía no es posible crear unos apliques swing sin cargar plugins en los navegadores.

En los textos de swing es posible introducir incluso imágenes y, además, se pueden leer y decodificar directamente los archivos de html, rtf (Un primo de .doc).

En Swing está la clase Jdialog, parecida a la Applet de java.applet. Es una extensión y presenta, además de los métodos de la clase Applet (de la que es una extensión), otros métodos muy interesantes, entre ellos el método void setJMenuBar(JMenuBar menuBar).

Obviamente, como hay muchos GUI más en swing, es necesario gestionar los sucesos. Para esto está el paquete de java.awt.event que gestiona dichos sucesos.




Fundamentos para el dibujo con Java


 
En el capítulo anterior hemos visto cómo utilizar los componentes GUI de Abstract Window Toolkit para construir unas interfaces gráficas para el usuario de nuestros programas, y hemos dicho que un componente GUI es, en suma, un objeto con unas cualidades gráficas. El componente GUI es de nivel alto en el paquete awt, y se construye utilizando los componentes de nivel bajo del paquete, es decir, las primitivas gráficas y los sucesos.
Pensemos, por ejemplo, en un botón. Éste, gráficamente, no es otra cosa que una caja con dentro un texto, que cambia aspecto cuando se aprieta, es decir, cuando escucha su suceso ActionEvent.
Utilizando las características de bajo nivel podemos construir nuestros GUI personalizados o modificar los que ya existen según nuestras necesidades. No solamente podemos extender un componente particular, un componente lienzo, en el que podemos dibujar lo que queramos y ponerlo en nuestras interfaces como cualquier otro GUI.
Si utilizamos los apliques más que las aplicaciones, podemos evitar utilizar el lienzo porque el aplique trae implícitamente un lienzo. De todas formas, empecemos a ver en concreto cómo se puede dibujar en un componente cualquiera o en un aplique. Primero hablaremos de los apliques y luego pasaremos a los componentes en general.




Las funciones paint, repaint y update...


En el lenguaje Java es posible dibujar en un aplique simplemente volviendo a definir el método paint. Este método se invoca automáticamente por el sistema cuando la ventana que incluye el aplique pasa a un primer plano. Por lo tanto cada orden gráfica al aplique se dará en el método paint del aplique.

void paint (Graphics g)
{
// Dibujo
}

Cuando el aplique haya dibujado y se quiera visualizar posibles cambios, es posible invocar el método repaint() o el método update(Graphics g) que borra el área en el que el aplique ha dibujado y vuelve a invocar la paint.
El método paint(Graphics g) no se puede invocar directamente.
El aplique no sólo tiene el método paint que se puede volver a definir, sino también los objetos de tipo Component, es decir, todos los GUI. Por lo tanto, para cambiar el aspecto gráfico de cualquier componente gráfico, basta con volver a definir el método paint.
Entre todos los componentes está el ya citado lienzo sobre el que es posible dibujar. Es un objeto de la clase Canvas. Los que están acostumbrados a programar con otros lenguajes esperan que en la paint haya un inicializador del device en el que se va a dibujar y, después, una serie de instrucciones de tipo drawLine, drawBox etc., sin embargo, os tengo que decir que esto no siempre es verdad, es decir, que en los componentes y en los apliques no hay ningún método gráfico.
Llegados a este punto, queda claro incluso que el parámetro g de tipo Graphics de la paint incluye los métodos gráficos que Java puede utilizar y representar, por decirlo de alguna forma, el área en el que se dibujarán las primitivas.
Graphics es una clase que no se puede incluir, sino que es recibida por la paint como parámetro. Por lo tanto se puede utilizar sólo en ella y sus métodos son:

abstract void clearRect(int x, int y, int width, int height)
abstract void clipRect(int x, int y, int width, int height)
abstract void copyArea(int x, int y, int width, int height, int dx, int dy)
abstract Graphics create()
Graphics create(int x, int y, int width, int height)
abstract void dispose()
void draw3DRect(int x, int y, int width, int height,boolean raised)
abstract void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)
void drawBytes(byte[] data, int offset, int length, int x, int y)
void drawChars(char[] data, int offset, int length, int x, int y)
abstract boolean drawImage(…) Ne esistono varie versioni
abstract void drawLine(int x1, int y1, int x2, int y2)
abstract void drawOval(int x, int y, int width, int height)
abstract void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
void drawPolygon(Polygon p)
abstract void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
void drawRect(int x, int y, int width, int height)
abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)
abstract void drawString(AttributedCharacterIterator iterator, int x, int y)
abstract void drawString(String str, int x, int y)
void fill3DRect(int x, int y, int width, int height, boolean raised)
abstract void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
abstract void fillOval(int x, int y, int width, int height)
abstract void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
void fillPolygon(Polygon p)
abstract void fillRect(int x, int y, int width, int height)
abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)
void finalize()
abstract Shape getClip()
abstract Rectangle getClipBounds()
Rectangle getClipBounds(Rectangle r)
abstract Color getColor()
abstract Font getFont()
FontMetrics getFontMetrics()
abstract FontMetrics getFontMetrics(Font f)
boolean hitClip(int x, int y, int width, int height)
abstract void setClip(int x, int y, int width, int height)
abstract void setClip(Shape clip)
abstract void setColor(Color c)
abstract void setFont(Font font)
abstract void setPaintMode()
abstract void setXORMode(Color c1)
String toString()
abstract void translate(int x, int y)

Dentro de poco veremos con detalle todos estos métodos.
En Java2 la clase Graphics ha sido potenciada añadiendo la clase Graphics2D, que la amplía añadiendo muchas posibilidades a la gráfica de Java.
Para tener una pequeña muestra de las potencialidades de Java podéis ver la Demo que está junto a las JDK. Si, por ejemplo, habéis bajado las JDK1.3 y las habéis instalado en c:jdk1.3, la demo está en:

c:jdk1.3demojfcJava2D

y para ponerla en marcha hay que escribir del prompt:

java -jar Java2Demo.jar





  
Visualización de las imágenes


Empezamos viendo los métodos drawImage de la clase Graphics con los que es posible visualizar unas imágenes guardadas con formato gif o jpg.
En la clase Graphics hay varios mátodos drawImage que son:

abstract boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) abstract boolean drawImage(Image img, int x, int y, ImageObserver observer)
abstract boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer)
abstract boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)
abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer)
abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer)

Todos los métodos requieren dos parámetros Image y ImageObserver.
Image rapresenta la imagen que hay que visualizar. Es una clase abstracta que permite un acceso independiente del formato de imágenes gráficas. Los objetos de esta clase se crean utilizando los métodos de otras clases que crean imágenes, según el contexto en el que se quieran utilizar.
Por ejemplo, si quiero dibujar una imagen en un componente Gui, puedo usar el método createImage() de la clase Component.
En cambio, si quiero dibujar una imagen en un aplique, es posible usar el método getImage() de la clase Applet.
La clase Toolkit tiene tanto createImage() como getImage().
El otro parámetro que necesitan las drawImage() es un objeto que implementa la interfaz ImageObserver, y en la práctica representa el objeto gráfico sobre el que se visualizará la imagen.
Component implementa la interfaz ImageObserver y, consecuentemente, la implementan todas sus extensiones:

Todos los GUI
Los Apliques
Todas las ventanas (incluso los Frames)

Los demás parámetros son:

la posición x en la que se visualizará la imagen en el componente
la posición y en la que se visualizará la imagen en el componente el color del fondo

Vamos a poner un ejemplo de visualización de una imagen. En primer lugar creamos una imagen como la siguiente:



y la guardamos en formato gif usando un editor cualquiera de imágenes llamándola, por ejemplo, pietro.jpg.
Ahora creamos el siguiente aplique:

import java.awt.*; // Para la clase Graphics
import java.applet.*; // Para la clase Applet
import java.net.*; // Para las URL
/*
Como hemos tenido ya la ocasión de decir, los archivos para los apliques no son otra cosa que unas URL
*/

public class VisualizaImagen extends Applet
{
Image ImagenPietro;

public void init()
{

setBackground(Color.white);

ImagenPietro=getImage(getDocumentBase(),"pietro.jpg");

}

public void paint(Graphics g)
{

g.drawImage(ImagenPietro,0,0,this);
getAppletContext().showStatus("Visualizo la imagen pietro.jpg, Applet creada por Pietro Castellucci");

}

}

La ponemos en un archivo llamado VisualizaImagen.java y la invocamos usando el documento html siguiente (Imagen.html):

<html>
<head>
<title>
Applet VisualizaImagen, visualiza la imagen pietro.jpg
</title>
</head>
<body>
<APPLET code="VisualizaImagen.class" width=385 height=100>
</APPLET>
<BR>
La de arriba es un aplique, sin embargo la de abajo no lo es.
<BR>
<IMG SRC="pietro.jpg">
</body>
</html>

Si ponemos en marcha el aplique nos damos cuenta de que no hay ninguna diferencia entre la imagen cargada en el aplique y la que hemos cargado usando el tag IMG SRC del html, sino el mensaje que aparece cuando pasamos por encima el ratón. Os podría parecer incluso un trabajo inútil para vuestras páginas html.
Esto es absolutamente falso porque la imagen cargada en el aplique pertenece a un programa que puede hacer incluso cosas complejas. Por ejemplo, es posible añadir otros componentes GUI al aplique, o elaborar las imágenes mismas, como se ve en el ejemplo sucesivo (VisualizaImagen2.java):

import java.awt.*; // Para la clase Graphics
import java.applet.*; // Para la clase Applet
import java.net.*; // Para las URL
import java.awt.event.*; // Para los sucesos

/*
Como ya hemos dicho, los archivos para los apliques no son otra cosa que unas URL
*/

public class VisualizaImagen2 extends Applet
{
Image ImagenPietro;

CheckboxGroup gruppo=new CheckboxGroup();

Checkbox b1=new Checkbox("Parar",grupo,true);

Checkbox b2=new Checkbox("Animada",grupo,false);

Panel p=new Panel(new GridLayout(1,3));

public void init()
{

setBackground(Color.white);
setLayout(new BorderLayout());
ImagenPietro=getImage(getDocumentBase(),"pietro.jpg");

p.add(new Label());
p.add(b1);
p.add(b2);

b1.addItemListener(new IL());
b2.addItemListener(new IL());

add(p,BorderLayout.SOUTH);

}

boolean MOVIMIENTO=false;

ent número=0;

ent inc=1;

public void paint(Graphics g)
{

if (!MOVIMIENTO)
{
g.drawImage(ImagenPietro,0,0,this);

getAppletContext().showStatus("Visualizo la imagen pietro.jpg, Imagen inmóvil, Applet creada Pietro Castellucci");

número=0;

}
else
{

g.setPaintMode();
g.drawImage(Elabora(ImagenPietro,número),0,0,this);

for (int k=0;k<=99;k++) getAppletContext().showStatus("Visualizo la imagen pietro.jpg, Frame "+número+", Applet creada por Pietro Castellucci");

getAppletContext().showStatus("Visualizo la imagen pietro.jpg, Frame "+número+", Applet creada por Pietro Castellucci");

if (número>=10) inc=-1;

if (número<=0) inc=1;

número+=inc;

}

repaint();

}


Image Elabora (Image img, int frm)
{

return img.getScaledInstance(324-(frm*20), 85-(frm*4),img.SCALE_FAST);

}


public class IL implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{

if (b1.getState()) MOVIMIENTO=false;
else MOVIMIENTO=true;
repaint();
}

}
}

Cargada por el archivo html siguiente:

<html>
<head>
<title>
Applet VisualizaImagen, visualiza la imagen pietro.jpg
</title>
</head>
<body>
<APPLET code="VisualizaImagen2.class" width=385 height=100>
</APPLET>
<BR>
La de arriba es un aplique, sin embargo la de abajo no lo es
<BR>
<IMG SRC="pietro.jpg">
</body>
</html>

La nueva clase Graphics2D pone a disposición otros métodos drawImage, entre los que hay algunos que tienen un parámetro de tipo AffineTransform que, como dice el nombre, es una transformación parecida a la de la imagen, una rotación o una translación, o una combinación de todas.

Para tener una versión sin revoloteo basta con añadir la función:

public void update(Graphics g)
{
paint(g);

}





Dibujo


Entendido el funcionamiento de la paint() podemos dibujar cualquier cosa en un aplique o en un componente en general.

La cosa más simple que se puede dibujar es la línea. Para hacerlo, utilizamos el método drawLine() de Graphics:

drawLine(Iniciox, Inicioy, Finx, Finy)

Éste dibuja una línea que parte de un punto (Iniciox, Inicioy) y llega a otro punto (Finx, Finy).
Antes de utilizar la drawLine() tenemos que comprender cómo se pueden cambiar los colores de las cosas que dibujamos.
Los colores se cambian utilizando el método setColor(Color c) de la clase Graphics.
Color es otra clase de awt que permite definir un color. Algunos de sus constructores son:

Color(float r, float g, float b), crea un color especificando los valores RGB (Red - Green - Blue, es decir, Rojo - Verde - Azul) con unos valores entre 0 y 1.

Color(float r, float g, float b, float a), como el anterior, sólo que permite definir incluso el valor alfa

Color(int r, int g, int b) , crea un color especificando los valores RGB (Red - Green - Blue, es decir, Rojo - Verde - Azul) con valores entre 0 y 255.

Color(int r, int g, int b, int a), como el anterior, sólo que permite definir incluso el valor alfa

Algunos colores simples se dan a través de unas constantes en la clase color:

Color.black
Color.blue
Color.cyan
Color.darkGray
Color.gray
Color.green
Color.lightGray
Color.magenta
Color.orange
Color.pink
Color.red
Color.white
Color.yellow

En el siguiente aplique se dibujan unas líneas de colores.

import java.awt.Graphics;

import java.awt.Color;

import java.awt.Button;

import java.awt.BorderLayout;

import java.awt.GridLayout;

import java.awt.Panel;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.applet.*;

public class líneas extends Applet
{

final ent SI=14;

final ent NO=0;

Button R=new Button("Rojo");

Button G=new Button("Verde");

Button B=new Button("Azul");

ent r_=0;

ent g_=0;

ent b_=0;

ent ir=0;

ent ig=0;

ent ib=0;

public void init()
{

setLayout(new BorderLayout());

Panel np=new Panel(new GridLayout(1,3));

np.add(R);

np.add(G);

np.add(B);

R.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{

ir=SÍ;
ig=NO;
ib=NO;
repaint();
}
}

);



G.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{

ir=NO;
ig=SÍ;
ib=NO;
repaint();
}
}

);


B.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{

ir=NO;
ig=NO;
ib=SÍ;
repaint();
}
}

);




add(np,BorderLayout.SOUTH);

}

public void paint(Graphics g)
{


for (ent e=0;e<200;e+=10)
{

g.setColor(new Color(r_,g_,b_));

r_=r_+ir;
g_=g_+ig;
b_=b_+ib;

g.drawLine(0,i,i,200);

}

g.setColor(Color.black);
g.drawLine(0,0,0,200);
g.drawLine(0,200,200,200);

r_=0;
g_=0;
b_=0;

}

}

El archivo lo llamamos líneas.java y lo cargamos con el archivo html siguiente (líneas.html):

<html>
<head>
<title>
Applet Líneas (líneas.class)
</title>
</head>
<body>
<APPLET code="lineas.class" width=200 height=300>
</APPLET>
</body>
</html>




Figuras geométricas y texto



RECTÁNGULOS

Graphics permite dibujar unos rectángulos especificando dos aristas opuestas usando el método:

drawRect(Iniciox,Inicioy,Finx,Finy);

Este método es igual a:

drawLine(Iniciox,Inicioy,Finx,Inicioy);
drawLine(Iniciox,Inicioy,Iniciox,Finy);
drawLine(Finx,Inicioy,Finx,Finy);
drawLine(Iniciox,Finy,Finx,Finy);

Es posible incluso construir rectángulos que den un efecto levantado o ahuecado usando el método draw3DRect(ent x,ent y,int anchura,ent altura,boolean levantado) y rectángulos con las aristas redondeadas con el método drawRoundRect(ent x, ent y, ent anchura, ent altura, ent anchuraArco, ent alturaArco).
Además es posible colorear en todas las figuras cerradas usando los métodos fill. Por ejemplo, para colorear un RoundRect hay que utilizar fillRoundRect, que tiene los mismos parámetros que la correspondiente draw.

CÍRCULOS Y ELIPSIS

Se puede dibujar una elipsis usando la drawOval (ent x, ent y, ent anchura,ent altura) y colorearla usando la fillOval(ent x, ent y, ent anchura,ent altura).
Si la altura y la anchura son iguales se dibuja un círculo.

POLÍGONOS

Usando la drawPolygon se dibuja un polígono genérico. Hay dos tipos de drawPolygon:

drawPoligon( ent[] PUNTOSx, ent PUNTOSy, ent NUMEROSPUNTOS);

e

drawPolygon (Polygon p)

La segunda usa un objeto de la clase Polygon que define un polígono. Están las correspondientes fillPolygon.

TEXTO

Para dibujar una cadena se puede utilizar el método drawString (String TEXTO, ent x, ent y);
Un texto se puede dibujar con distintas Font. Para cambiar las Font Graphics pone a disposición el método setFont(Font font), en el que font es el objeto que define el tipo de carácter.
Font es la clase que define los caracteres y es posible invocarla creando un Font específico, usando Font(String name, ent style, ent size).
Font es una clase bastante complicada, sin embargo es fácil encontrar y usar los Fonts del sistema mientras se pone en marcha programma java: En las viejas versiones de java basta con escribir:

String [] NOMBRES=Toolkit.getDefaultToolkit().getFontList();

Mientras en las nuevas versiones de Java (de JDK 1.2 )

String [] NOMBRES=GraphicsEnvironment.
getLocalGraphicsEnvironment().
getAvailableFontFamilyNames();

Además es fácil escribir objetos sabiendo los nombres.

ARCOS

Puedo dibujar unos arcos usando drawArc(ent x, ent y, ent anchura, ent altura, ent ánguloInicial, ent ánguloArco)

El uso de todos estos métodos se explica en el ejemplo que ponemos a continuación.
El archivo que lo pone en marcha es:

<html>
<head>
<title>
Applet grafDemo (grafDemo.class)
</title>
</head>
<body>
<APPLET code="grafDemo.class" width=500 height=400>
</APPLET>
</body>
</html>


Archivo grafDemo.java


 
El ejemplo, editado en el archivo grafDemo.java, es:

import java.awt.Graphics;

import java.awt.Color;

import java.awt.Button;

import java.awt.BorderLayout;

import java.awt.GridLayout;

import java.awt.FlowLayout;

import java.awt.Panel;

import java.awt.Label;

import java.awt.Choice;

import java.awt.Font;

import java.awt.Toolkit;

import java.awt.Checkbox;

import java.awt.Scrollbar;

import java.awt.GraphicsEnvironment;

import java.awt.event.ItemEvent;

import java.awt.event.ItemListener;

import java.awt.event.AdjustmentListener;

import java.awt.event.AdjustmentEvent;

import java.applet.*;

public class grafDemo extends Applet
{

Scrollbar R=new Scrollbar(Scrollbar.VERTICAL, 0, 1, 0, 255);

Scrollbar G=new Scrollbar(Scrollbar.VERTICAL, 0, 1, 0, 255);

Scrollbar B=new Scrollbar(Scrollbar.VERTICAL, 0, 1, 0, 255);

Choice FN=new Choice();

Choice GR=new Choice();

Checkbox F=new Checkbox("Figuras cerradas llenas",false);

ent [] puntosX={1,100,200,300,399,300,200,100};

ent [] puntosY={200,150,50,150,200,100,250,130};

ent puntos=8;

public void init()
{

// Calculo los Font del sistema:

// String[] NOMBRES=GraphicsEnvironment.
// getLocalGraphicsEnvironment().
// getAvailableFontFamilyNames();

/*
Para Java presentes en los browser
String [] NOMBRES=Toolkit.getDefaultToolkit().getFontList();
*/

String [] NOMBRES=Toolkit.getDefaultToolkit().getFontList();

try
{
ent índice=0;

while (true)
{

FN.addItem(NOMBRES[índice++]);

}

}
catch (ArrayIndexOutOfBoundsException e)
{};

setLayout(new BorderLayout());

Panel np=new Panel(new GridLayout(1,3));


Panel rojo=new Panel(new FlowLayout());
rojo.add(new Label("Rojo"));
rojo.add(R);
np.add(rojo);

Panel verde=new Panel(new FlowLayout());
verde.add(new Label("Verde"));
verde.add(G);
np.add(verde);

Panel azul=new Panel(new FlowLayout());
azul.add(new Label("Azul"));
azul.add(B);
np.add(azul);

R.setUnitIncrement(10);
R.setValue(255);

G.setUnitIncrement(10);
G.setValue(255);

B.setUnitIncrement(10);
B.setValue(255);

add(np,BorderLayout.SOUTH);

GR.addItem("Línea");

GR.addItem("Rectángulo");

GR.addItem("Rectángulo 3D");

GR.addItem("Rectángulo Redondeado");

GR.addItem("Círculo");

GR.addItem("Elípses");

GR.addItem("Polígono genérico");

GR.addItem("Texto");

GR.addItem("Arco");

Panel up=new Panel(new GridLayout(1,3));

up.add(GR);

up.add(FN);

up.add(F);

add(up,BorderLayout.NORTH);

R.addAdjustmentListener(new AL());

G.addAdjustmentListener(new AL());

B.addAdjustmentListener(new AL());

GR.addItemListener(new IL());

FN.addItemListener(new IL());

F.addItemListener(new IL());

}


public void paint(Graphics g)
{

g.setColor(new Color(255-R.getValue(),
255-G.getValue(),
255-B.getValue()
));

g.setFont(new Font(FN.getSelectedItem(),0,40));

boolean filled=F.getState();

int pg=GR.getSelectedIndex();

g.drawString(GR.getSelectedItem(),1,300);

if (pg==0)
{
g.drawLine(1,100,399,300);
return;
}

if (pg==1)
{
g.drawRect(50,100,250,100);
if (filled) g.fillRect(50,100,250,100);
return;
}

if (pg==2)
{
g.draw3DRect(50,100,250,100,true);
return;
}

if (pg==3)
{
g.drawRoundRect(50,100,300,100,20,20);
if (filled) g.fillRoundRect(50,100,300,100,20,20);
return;
}

if (pg==4)
{
g.drawOval(100,100,200,200);
if (filled) g.fillOval(100,100,200,200);
return;
}

if (pg==5)
{
g.drawOval(100,100,200,100);
if (filled) g.fillOval(100,100,200,100);
return;
}

if (pg==6)
{
g.drawPolygon(puntosX,puntosY,puntos);
if (filled) g.fillPolygon(puntosX,puntosY,puntos);
return;
}


if (pg==7)
{
g.drawString("Ésta es una cadena",1,200);
return;
}

if (pg==8)
{
g.drawArc(1,50,398,200,10,270);
if (filled) g.fillArc(1,50,398,200,10,270);
return;
}




}

public class IL implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{
repaint();
}

}

public class AL implements AdjustmentListener
{
public void adjustmentValueChanged(AdjustmentEvent e)
{
repaint();
}

}


}




Notas para redactar el programa


 
Visto que el programa ha sido creado para un navegador (que tiene las versiones de Java) se ha tenido que utilizar String [] NOMBRES=Toolkit.getDefaultToolkit().getFontList(); para obtener los caracteres, si se redacta con JDK 1.2 o 1.3 se tiene que escribir:

Ø javac grafDemo.java -deprecation

Esto dará un aviso para decir que se usa un método deprecated.
Si, en cambio, utilizáis el appletviewer para visualizar el aplique, podéis cambiar

String [] NOMBRES=Toolkit.getDefaultToolkit().getFontList();

con

String [] NOMBRES=GraphicsEnvironment.
getLocalGraphicsEnvironment().
getAvailableFontFamilyNames();

y apreciar la gran cantidad de Font que hay.

En el ejemplo, he utilizado los colores de scrollbar, entre ellos los GUI que no hemos visto. Para crear el objeto scrollbar he utilizado el constructor:

Scrollbar R=new Scrollbar(Scrollbar.VERTICAL, 0, 1, 0, 255);

que crea una barra (scrollbar) vertical con valores entre 0 y 255 con valor inicial 0.
Después he averiguado el valor de la barra con R.setValue(255); he dicho que el incremento por cada clic tiene que ser 10 con R.setUnitIncrement(10);

Para escuchar los cambios, utilizo un objeto que implementa la clase AdjustmentListener que, a su vez, escucha los sucesos de tipo AdjustmentEvent. Para asociar el oyente al objeto scrollbar se utiliza el método addAdjustmentListener.



El sonido de Java 1.1.x y 1.2.x


Hasta ahora hemos intentado crear programas compatibles entre las viejas y las nuevas versiones de Java. Esto para crear unos apliques generales que puedan trabajar en todos los browser (que tienen actualmente Java 1.1.x come motor para los apliques).
En el apartado que estamos a punto de tratar, desgraciadamente esto no es posible. Con las viejas versiones de Java se pueden crear unos apliques que leen y tocan archivos de tipo .au, usando los métodos play de applet y la interfaz AudioClip.
Todo esto es posible todavía con Java2, versión 1.3, sin embargo se han incluido unos paquetes para gestionar los sonidos que ofrecen potencialidades excepcionales.




El sonido en jdk1.3: javax.swing.sampled


 
Los paquetes que se han añadido al lenguaje son 4:

javax.sound.midi
javax.sound.midi.spi
javax.sound.sampled
javax.sound.sampled.spi
Las partes que acaban por spi sirven para leer archivos sonoros, convertirlos o leer los archivos de instrumentos en el caso de midi. Nosotros no vamos a ver estás partes, sin embargo veremos javax.sound.sampled y javax.sound.midi.
El paquete javax.swing.sampled permite grabar, tocar y modificar datos sonoros.
El contenido del paquete es:

Interfaces
Clip
DataLine
Line
LineListener
Mixer
Port
SourceDataLine
TargetDataLine
Clases
AudioFileFormat
AudioFileFormat.Type
AudioFormat
AudioFormat.Encoding
AudioInputStream
AudioPermission
AudioSystem
BooleanControl
BooleanControl.Type
CompoundControl
CompoundControl.Type
Control
Control.Type
DataLine.Info
EnumControl
EnumControl.Type
FloatControl
FloatControl.Type
Line.Info
LineEvent
LineEvent.Type
Mixer.Info
Port.Info
ReverbType
Excepciones
LineUnavailableException
UnsupportedAudioFileException
Vamos a ver cómo utilizar este paquete sólo para tocar un archivo sonoro, por ejemplo, el archivo llamado italian.wav.

En primer lugar, tenemos que buscar el archivo y esto lo hacemos, como siempre, introduciendo un objeto de la clase File (de java.io)

File sf=new File("italian.wav");

Llegados a este punto, empezamos una try{} catch, en la que incluimos todo lo que tiene que ver con el sonido. Después capturaremos las excepciones:

catch(UnsupportedAudioFileException ee){}
catch(IOException ea){}
catch(LineUnavailableException LUE){};

Para usar el motor sonoro de Java tenemos que empezar por la clase AudioSystem y de ésta obtendremos dos objetos de tipo AudioFileFormat y AudioInputStream

AudioFileFormat aff=AudioSystem.getAudioFileFormat(sf);
AudioInputStream ais=AudioSystem.getAudioInputStream(sf);

que representan el contenido del archivo italian.wav

tenemos que crear un objeto AudioFormat de AudioFileFormat para que se pueda tocar

AudioFormat af=aff.getFormat();

Nuestro objetivo es crear un objeto que implemente la interfaz Clip, que incluye los métodos play. Para hacer esto escribiremos:

DataLine.Info info = new DataLine.Info(
Clip.class,
ais.getFormat(),
((int) ais.getFrameLength() *
af.getFrameSize()));

Clip ol = (Clip) AudioSystem.getLine(info); De ol, que es el tipo Clip, podemos tocar y esto se consigue abriendo una línea e invocando los métodos para tocar:

ol.open(ais); <-(ABRIR l'input stream, es decir, el archivo italian.wav)

y, por lo tanto

ol.loop(NÚMERO);

en el que NÚMERO indica el número de repeticiones del archivo, en nuestro caso, Clip. LOOP_CONTINUOUSLY para indicar que se tiene que repetir infinitas veces.

El ejemplo completo, editado en sonido.java es:

import javax.swing.*;
import javax.sound.sampled.*;
import java.io.*;

public class sonido extends JFrame
{


public sonido()
{

File sf=new File("italian.wav");
AudioFileFormat aff;
AudioInputStream ais;


try
{
aff=AudioSystem.getAudioFileFormat(sf);

ais=AudioSystem.getAudioInputStream(sf);


AudioFormat af=aff.getFormat();


DataLine.Info info = new DataLine.Info(
Clip.class,
ais.getFormat(),
((int) ais.getFrameLength() *
af.getFrameSize()));

Clip ol = (Clip) AudioSystem.getLine(info);

ol.open(ais);

ol.loop(Clip.LOOP_CONTINUOUSLY);

System.out.println("reprodución empezada, apretar CTRL-C para interrumpir");

}
catch(UnsupportedAudioFileException ee){}
catch(IOException ea){}
catch(LineUnavailableException LUE){};

}

public static void main(String[] ar)
{
new sonido();

}

}

Parece un poco trabajoso, sin embargo, siguiendo estos pasos es posible leer y tocar cada archivo wav. Para hacer otras operaciones, el paquete es bastante complejo y actualmente no hay manuales que expliquen el funcionamiento (excepto la documentación del JDK que, como habéis tenido la oportunidad de ver, no explica cómo utilizar las cosas, sino que las describe y punto).



El paquete javax.suond.midi


 
Vamos a ver cómo leer y tocar un archivo midi. Para hacerlo necesitamos el paquete javax.suond.midi que incluye:

Interfaces

ControllerEventListener
MetaEventListener
MidiChannel
MidiDevice
Receiver
Sequencer
Soundbank
Synthesizer
Transmitter
Clases

Instrument
MetaMessage
MidiDevice.Info
MidiEvent
MidiFileFormat
MidiMessage
MidiSystem
Patch
Sequence
Sequencer.SyncMode
ShortMessage
SoundbankResource
SysexMessage
Track
VoiceStatus
Excepciones

InvalidMidiDataException
MidiUnavailableException
La técnica para tocar un archivo midi es parecida a la que se usa para el archivo wav, lo único diferente es que se parte de MidiSystem.

En el ejemplo que ponemos a continuación, se toca el archivo sorpresa.mid, que es un archivo midi que me gusta mucho y, creo, le va a gustar a todos mis coetáneos.
Hay que editarlo en el archivo midifiles.java

import javax.swing.*;
import javax.sound.midi.*;
import java.io.*;

public class midifiles extends JFrame
{

public midifiles()
{
try
{

File f2=new File("sorpresa.mid");

MidiFileFormat mff2=MidiSystem.getMidiFileFormat(f2);

Sequence S=MidiSystem.getSequence(f2);

Sequencer seq=MidiSystem.getSequencer();

seq.open();

seq.setSequence(S);

seq.start();

System.out.println("Sorpresa para todos mis coetáneos");
System.out.println("Apretar CTRL-C para interrumpir");



}
catch(MidiUnavailableException ecc){}
catch(InvalidMidiDataException ecc2){}
catch(IOException ecc3){}
;
}


public static void main(String[] ar)
{
new midifiles();

}

}




Sintetizar los sonidos


Como ya he dicho, es posible sintetizar los sonidos. Esto es lo que hace el próximo programa que hay que editar en el archivo sintetizador.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;
import java.yo.*;
import java.util.*;
import javax.sound.sampled.*;
import javax.sound.midi.*;

public class sintetizador extends JFrame
{

ent TIEMPO=50;
ent CANAL=0;
ent UNS=-1;
ent INSTRUMENTO=0;
Sintetizador SINTETIZADOR=new Sintetizador();

// GUI

JLabel teclado1=new JLabel(new ImageIcon("teclado1.gif"));
JLabel teclado2=new JLabel(new ImageIcon("teclado2.gif"));

JButton OkB=new JButton("Ok");


JComboBox Instrumentos=new JComboBox();
JComboBox Canales=new JComboBox();

JLabel uns=new JLabel("Última nota tocada");
JTextField msg=new JTextField(
"Ninguna nota"
);

JSlider SL=new JSlider();

public sintetizador()
{
setTitle("Sintetizador sonoro de Pietro Castellucci");

setupAspecto();

setupValores();

setupSucesos();

SINTETIZADOR.setInstrumento(
Instrumentos.getSelectedIndex(),CANAL);

setResizable(false);

setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

pack();

Toolkit t = Toolkit.getDefaultToolkit();

Dimension d=t.getScreenSize();

Dimension win=getSize();

win=getSize();

setLocation(d.width/2-(win.width/2)-1,d.height/2-(win.height/2)-1);

show();

}


void setupAspecto()
{
teclado1.setCursor(new Cursor(Cursor.HAND_CURSOR));
teclado2.setCursor(new Cursor(Cursor.HAND_CURSOR));
OkB.setCursor(new Cursor(Cursor.HAND_CURSOR));

tastiera1.setToolTipText(
"Clícame para tocar"
);

tastiera2.setToolTipText(
"Clícame para tocar"
);

OkB.setToolTipText(
"Salir del programa"
);



JPanel P=new JPanel(new BorderLayout());
JPanel Panel=new JPanel(new GridLayout(2,1));
Panel.add(teclado1);
Panel.add(teclado2);

P.add(Panel,BorderLayout.CENTER);

JPanel SP=new JPanel(new FlowLayout());

Instrumentos.setBorder(
BorderFactory.createTitledBorder(
"Instrumentos"
)
);

Canales.setBorder(
BorderFactory.createTitledBorder(
"Canales"
)
);

SP.add(Instrumentos);
// SP.add(Canales);

SP.add(uns);
msg.setEditable(false);
msg.setBackground(P.getBackground());
SP.add(msg);

SP.add(OkB);

P.add(SP,BorderLayout.SOUTH);

SL.setBorder(BorderFactory.createTitledBorder(
"Presión "
));

SL.setOrientation(JSlider.VERTICAL);

SL.setMajorTickSpacing(25);
SL.setMaximum(100);
SL.setMinimum(0);
SL.setMinorTickSpacing(1);

SL.setPaintLabels(true);
SL.setPaintTicks(true);
SL.setPaintTrack(true);
SL.setSnapToTicks(true);

SL.setValue(TIEMPO);

P.add(SL,BorderLayout.EAST);


setContentPane(P);
}




void setupValores()
{
try
{
ent e=0;
while (true)
{
String nombre= SINTETIZADOR.Instrumentos[i++].getName();
Instrumentos.addItem(nombre);
}
}
catch (ArrayIndexOutOfBoundsException e)
{};



try
{
int i=0;
while (true)
{
String nombre="Canales"+" "+(i+1);
SINTETIZADOR.CANALES[i++].allNotesOff();
Canales.addItem(nombre);
}
}
catch (ArrayIndexOutOfBoundsException e)
{};

if (Instrumentos.getItemCount()>0)
Instrumentos.setSelectedIndex(INSTRUMENTO);
}




void setupSucesos()
{
teclado1.addMouseListener(new Teclado1Listener());
teclado2.addMouseListener(new Teclado2Listener());




Instrumentos.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{

SINTETIZADOR.setInstrumento(
Instrumentos.getSelectedIndex(),CANALES);

}
}
);



Canales.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
CANALES=Canales.getSelectedIndex();
SINTETIZADOR.cambiaCanal(CANAL);
}
});



OkB.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("¡Gracias por haber tocado conmigo!");
System.exit(0);
}
}
);





}

// Sucesos


public class Teclado1Listener implements MouseListener
{
public void mouseClicked(MouseEvent e)
{}

public void mouseEntered(MouseEvent e)
{}

public void mouseExited(MouseEvent e)
{}

public void mousePressed(MouseEvent e)
{
// System.out.println("Teclado 1 Punto: (x="+e.getX()+",y="+e.getY()+")");
UNS=getNota(e.getX());
// System.out.println("Nota="+nota);
TIEMPO=SL.getValue();
SINTETIZADOR.tocar(UNS,TIEMPO,CANAL);
msg.setText(""+(UNS+1));
}

public void mouseReleased(MouseEvent e)
{}

}


public class Teclado2Listener implements MouseListener
{
public void mouseClicked(MouseEvent e)
{}

public void mouseEntered(MouseEvent e)
{}

public void mouseExited(MouseEvent e)
{}

public void mousePressed(MouseEvent e)
{
// System.out.println("Teclado 2 Punto: (x="+e.getX()+",y="+e.getY()+")");
UNS=64+getNota(e.getX());
// System.out.println("Nota="+nota);
TIEMPO=SL.getValue();
SINTETIZADOR.suona(UNS,TIEMPO,CANAL);
msg.setText(""+(UNS+1));
}

public void mouseReleased(MouseEvent e)
{}

}





// Utility fun

int getNota (int pos)
{
int nota;
nota=(pos/12);
return nota;
}




public static void main(String[] arg)
{

new sintetizador();

}


//*****************************************
// SOUND MANAGER
//*****************************************

//***********************************************************
// Sintetizador:
//***********************************************************

public class Sintetizador
{
private Synthesizer SYNT;
private Sequencer sequencer;
private Sequence seq;
private Soundbank BANK;
public Instrument[] Instrumentos;
public MidiChannel[] CANALES;

public Sintetizador()
{
setupSintetizador();
}

void setupSintetizador()
{
try
{
SYNT=MidiSystem.getSynthesizer();
sequencer=MidiSystem.getSequencer();
seq= new Sequence(Sequence.PPQ, 10);
SYNT.open();
BANK = SYNT.getDefaultSoundbank();
if (BANK != null)
Instrumentos = SYNT.getDefaultSoundbank().getInstruments();
else
Instrumentos = SYNT.getAvailableInstruments();
CANALES=SYNT.getChannels();
}
catch(MidiUnavailableException ecc){todonull();}
catch(InvalidMidiDataException ecc2){todonull();}
;
}

void todonull()
{
SYNT=null;
sequencer=null;
seq=null;
BANK=null;
Instrumentos=null;
}

public void setInstrumento(int str,int can)
{

SA=str;
int prog=Instrumentos[str].getPatch().getProgram();
CANALES[can].programChange(prog);

}

private int SA=0;

public void cambiaCanal(int can)
{
int prog=Instrumentos[SA].getPatch().getProgram();
CANALES[can].programChange(prog);
}

public void tocar(ent nota,ent tiempo, ent canal)
{
CANALES[canal].allNotesOff();
CANALES[canal].noteOn(nota,tiempo);
}

public void tocar(ent nota,ent tiempo)
{
tocar(nota,tiempo,0);
}

public void callar()
{
CANALES[0].allNotesOff();
}


} // End of Sintetizador

}

Os habéis dado cuenta de que es un programa consistente, sin embargo no tenéis que espantaros porque la mayor parte del código sirve para la gráfica y para escuchar los sucesos. La parte interesante para sintetizar los sonidos la he puesto en la subclase Sintetizador, es decir, en sintetizador.Sintetizador

es decir, la siguiente:

//***********************************************************
// Sintetizador:
//***********************************************************
public class Sintetizador
{
private Synthesizer SYNT;
private Sequencer sequencer;
private Sequence seq;
private Soundbank BANK;
public Instrument[] Instrumentos;
public MidiChannel[] CANALES;

public Sintetizador()
{
setupSintetizador();
}
void setupSintetizador()
{
try
{
SYNT=MidiSystem.getSynthesizer();
sequencer=MidiSystem.getSequencer();
seq= new Sequence(Sequence.PPQ, 10);
SYNT.open();
BANK = SYNT.getDefaultSoundbank();
if (BANK != null)
Instrumentos = SYNT.getDefaultSoundbank().getInstruments();
else
Instrumentos = SYNT.getAvailableInstruments();
CANALES=SYNT.getChannels();
}
catch(MidiUnavailableException ecc){todonull();}
catch(InvalidMidiDataException ecc2){todonull();}
;
}
void todonull()
{
SYNT=null;
sequencer=null;
seq=null;
BANK=null;
Instrumentos=null;
}
public void set nstrumento(ent str,ent can)
{

SA=str;
ent prog=Instrumentos[str].getPatch().getProgram();
CANALES[can].programChange(prog);

}
private ent SA=0;
public void cambiaCanal(ent can)
{
ent prog=Instrumentos[SA].getPatch().getProgram();
CANALES[can].programChange(prog);
}
public void tocar(ent nota,ent tiempo, ent canal)
{
CANALES[canal].allNotesOff();
CANALES[canal].noteOn(nota,tiempo);
}

public void tocar(ent nota,ent tiempo)
{
tocar(nota,tiempo,0);
}
public void callar()
{
CANALES[0].allNotesOff();
}
} // End of Sintetizador

El aspecto del programa es:









Conclusiones y bibliografía



Hemos hecho un resumen de algunas partes del famoso lenguaje Java, muy utilizado para escribir los programas que trabajan en internet y no sólo para eso; empezando por las bases hasta llegar a las interfaces gráficas y, finalmente, al sonido. Éstos son todos aspectos más avanzados de la programación.
Quiero disculparme con mis lectores menos expertos por si han tenido problemas para entender algunas partes de la guía y, al mismo tiempo, quiero hacerlo con los más expertos si han encontrado algo demasiado aburrido o simple. Los que han asistido a todo el curso tendrían que ser capaces de escribir unos apliques simples y unas aplicaciones por su cuenta. No creo que hayáis conseguido todavía gestionar grandes aplicaciones complejas, aunque, con un poco de práctica y con los simples conceptos del curso, os váis a convertir en excelentes programadores.
Yo estaré siempre disponible a posibles preguntas sobre el curso o a más explicaciones, pero os pido que no me escribáis para los Javascript o para la configuración de los apliques bajados de la red.
Para los que quieran profundizar los temas tratados o ver nuevos, os dejo la bibliografía completa en la que me he basado para preparar este curso.

Un saludo a todos.


Reinaldo Huarayo Carata
 (Chocky Hack)





Ejercicios Java


Este ejercicio en java divide un números sucesivamente hasta conseguir
el número de cifras que tiene un entero.

Por ejemplo si tu introduces el número 3454 el programa te devolverá
un 4.


import java.io.*;

class Cifras {

static int total=0;
static int x=0;

static int numCifras(int x){
while(x!=0){
x=x/10;
total+=1; //incrementamos el contador
}
return total;
}

public static void main(String[]args) throws IOException{
//BufferedReader para leer de consola
BufferedReader leer = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Introduce un nu4mero:");
//leemos una línea como string
String linea = leer.readLine();
/*Convertirmos el string a un número. Podrías poner
*un try y catch para comprobrar errores al convertirlo.Por
*ejemplo si introducen un string*/
x= Integer.parseInt(linea);
System.out.println("El numero de cifras es:");
//Imprimimos el número de líneas
System.out.println(numCifras(x));
}
}



Este ejemplo busca coincidencias en los archivos a partir de un directorio
especificado por el usuario.

Problema:
Si tenemos una aplicaciones que realiza un proceso que consume un tiempo relativamente largo, es bueno hacer saber al usuario de la aplicacion que la tarea esta siendo procesada y mas o menos el tiempo que queda, lo tipico del mensaje:'El proceso va por el 20%' por ejemplo.

Las librerias de Swing en java, tiene unos mecanismos para mostrar este progreso, vamos a hacer un ejemplo de una aplicacion que busca una cadena de texto en todos los ficheros de un directorio espedificado.



import java.awt.GridLayout;
import java.awt.Cursor;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import javax.swing.*;
import java.lang.reflect.InvocationTargetException; public class ProgressDemo {

String startdir; // directorio de busqueda
String patt; // lo que vamos a buscar
JTextArea outarea; // output area for file pathnames
JFrame frame; // frame
JProgressBar progbar; // barra de progreso
JLabel fileslab; // numero de ficheros encontrado
boolean search_flag; // true si la busqueda esta en progreso

class Search extends Thread
{

// actualiza el GUI
void doUpdate(Runnable r) {
try {
SwingUtilities.invokeAndWait(r);
}
catch (InvocationTargetException e1) {
System.err.println(e1);
}
catch (InterruptedException e2) {
System.err.println(e2);
}
}
// nos da la lista de los ficheros de un directorio
void getFileList(File f, List list) {

// recursividad si hay un directorio dentro del mismo
if (f.isDirectory()) {
String entries[] = f.list();
for (int i = 0; i < entries.length; i++) {
getFileList(new File(f, entries[i]),
list);
}
}

// para fciheros , se añaden a la lista y se actualiza la barra de progreso
else if (f.isFile()) {
list.add(f.getPath());
final int size = list.size();
if (size % 100 != 0) {
return;
}
doUpdate(new Runnable() {
public void run() {
progbar.setValue(size % 1000);
}
});
}
}

// comprueba que el fichero contiene la cadena
boolean fileMatch(String fn, String patt) {
boolean found = false;

try {
FileReader fr = new FileReader(fn);
BufferedReader br = new BufferedReader(fr);
String str;
while ((str = br.readLine()) != null) {
if (str.indexOf(patt) != -1) {
found = true;
break;
}
}
br.close();
}
catch (IOException e) {
System.err.println(e);
}
return found;
}



// realiza la busqueda
public void run() {
List filelist = new ArrayList();
final String sep =
System.getProperty("line.separator");

doUpdate(new Runnable() {
public void run() {
outarea.setText("");
fileslab.setText("");
}
});

// nos da la lista de todos los ficheros y muestra el contador
getFileList(new File(startdir), filelist);
final int size = filelist.size();
doUpdate(new Runnable() {
public void run() {
progbar.setValue(0);
fileslab.setText("Encontrados " + size +
" ficheros, buscando ...");
}
});

// configura el monitor de progreso
final ProgressMonitor pm = new ProgressMonitor(
frame, "Buscando ficheros", "", 0, size - 1);
pm.setMillisToDecideToPopup(0);
pm.setMillisToPopup(0);

// itera entre los ficheros, actualizando el monitor de progreso
for (int i = 0; i < size; i++) {
final String fn = (String)filelist.get(i);
final int curr = i;
if (pm.isCanceled()) {
break;
}
final boolean b = fileMatch(fn, patt);
doUpdate(new Runnable() {
public void run() {
pm.setProgress(curr);
pm.setNote(fn);
if (b) {
outarea.append(fn + sep);
}
}
});
}

doUpdate(new Runnable() {
public void run() {
pm.close();
outarea.setCaretPosition(0);
fileslab.setText("");
}
});
search_flag = false;
}
}

public ProgressDemo() {
frame = new JFrame("ProgressDemo");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});



JPanel paneltop = new JPanel();
JPanel panelbot = new JPanel();
paneltop.setLayout(new GridLayout(5, 1));
JPanel panel1 = new JPanel();
panel1.add(new JLabel("Directorio inicial"));
final JTextField dirfield = new JTextField(20);
panel1.add(dirfield);
JPanel panel2 = new JPanel();
panel2.add(new JLabel("Patron de busqueda"));
final JTextField pattfield = new JTextField(20);
panel2.add(pattfield);
JPanel panel3 = new JPanel();
JButton button = new JButton("Search");
panel3.add(button);
JPanel panel4 = new JPanel();
progbar = new JProgressBar(0, 999);
panel4.add(progbar);
JPanel panel5 = new JPanel();
fileslab = new JLabel();
panel5.add(fileslab);
JPanel panel6 = new JPanel();
outarea = new JTextArea(8, 40);
outarea.setEditable(false);
JScrollPane jsp = new JScrollPane(outarea,ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
panel6.add(jsp);

button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
startdir = dirfield.getText();
patt = pattfield.getText();
if (startdir == null ||
startdir.trim().equals("") ||
patt == null ||
patt.trim().equals("")) {
JOptionPane.showMessageDialog(
frame, "Entrada invalida", "Error",
JOptionPane.ERROR_MESSAGE);
}
else if (search_flag) {
JOptionPane.showMessageDialog(
frame, "Busqueda en progreso",
"Error", JOptionPane.ERROR_MESSAGE);
}
else {
search_flag = true;
new Search().start();
}
}
});

paneltop.add(panel1);
paneltop.add(panel2);
paneltop.add(panel3);
paneltop.add(panel4);
paneltop.add(panel5);
panelbot.add(panel6);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2, 1));
panel.add(paneltop);
panel.add(panelbot);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocation(200, 200);
frame.setVisible(true);
}

public static void main(String args[]) {
new ProgressDemo();
}
}





GridLayout

El GridLayout es una forma de situar los componentes con gran flexibilidad en el panel.
con setLayout(new GridLayout(Fila,Columna)); puedes establecer un layout con el número de Filas y Columnas y los componentes se añaden dentro de las celdas definidas.

En el siguiente ejemplo se colocan los componentes en una rejilla que ocupa todo el frame y coloca cuatro botones en su respectiva celda.

import javax.swing.*;
import java.awt.*;


class Ejemplo extends JFrame {
JButton uno = new JButton("uno");
JButton dos = new JButton("dos");
JButton tres = new JButton("tres");
JButton cuatro = new JButton("cuatro");

Menu(){
this.setLayout(new GridLayout(2,2));
add(uno);
add(dos);
add(tres);
add(cuatro);

setTitle("Ejemplos de GridLayout");
setSize(400,400);
setVisible(true);
}

public static void main (String []args){
new Ejemplo();
}

}





FlowLayout


El FlowLayout es el método más simple de colocar los componentes dentro de un Panel o un Jpanel en java. Cada uno de los componentes de un panel que se encuentran en FlowLayout se encuentran situados de izquierda a derecha como en una lista, unos a continuación de los otros, saltando hacia abajo cuando no hay espacio suficiente para ese componente.

FlowLayout pertenece a java.awt, pero tambien se puede aplicar a swing, por ejemplo como en este caso a un JPanel.

Un ejemplo de la utilización del FlowLayout en un programa para colocar tres botones en un panel.


import javax.swing.*;
import java.awt.*;


class Ejemplo extends JFrame {
JButton primero = new JButton("Primero");
JButton anterior = new JButton("Anterior");
JButton siguiente = new JButton("Siguiente");
JButton ultimo = new JButton("Ultimo");

Ejemplo(){
//Añadimos el formato de FlowLayout al JFrame
this.setLayout(new FlowLayout());
//Añadimos componentes
add(primero);
add(anterior);
add(siguiente);
add(ultimo);

setTitle("Ejemplos FlowLayout");
setSize(400,400);
setVisible(true);
}

public static void main (String []args){
new Ejemplo();
}

}




Por ejemplo para insertar una imagen en el botón de guardar utilizaremos:
ImageIcon ImagenGuardar=new ImageIcon("guardar.gif");
BGuardar.setIcon(ImagenGuardar);


import javax.swing.*;

class Menu extends JFrame {
//Toolbar
JToolBar TBarra=new JToolBar();
JButton BNuevo=new JButton("N");
JButton BAbrir=new JButton("A");
JButton BCopiar=new JButton("C");
JButton BCortar=new JButton("C");
JButton BPegar=new JButton("P");
JButton BGuardar=new JButton("G");
public Menu() {

//ToolBar
TBarra.add(BNuevo);
TBarra.add(BAbrir);
TBarra.add(BGuardar);
TBarra.addSeparator();
TBarra.add(BCopiar);
TBarra.add(BCortar);
TBarra.add(BPegar);
BGuardar.setToolTipText ("Guardar");
BNuevo.setToolTipText ("Nuevo");
BAbrir.setToolTipText ("Abrir");
BCopiar.setToolTipText ("Copiar");
BCortar.setToolTipText ("BCortar");
BPegar.setToolTipText ("Pegar");


add(TBarra,"North");

TBarra.setFloatable(false);
setTitle("Ejemplos JPopUpMenu");
setSize(800,600);
setVisible(true);
}

public static void main (String []args){
new Menu();
}

}


Radios Online Music-strike - - -

-
 
- - -
SISTEMA DE SONIDO
MALIBU



- -     - >center> -
www.reymondj.tk - - - - --
Este sitio web fue creado de forma gratuita con PaginaWebGratis.es. ¿Quieres también tu sitio web propio?
Registrarse gratis