|
| índice |
Java viene con un conjunto muy completo de librerías.
Éstas tienen un valor añadido muy importante, porque
las librerías son indispensables en un desarrollo llevado
con técnicas orientadas a objetos. Los que prefieren hacérselo
todo están de mala suerte, porque puede economizarse un
tiempo precioso de desarollo gracias a ello.
Las librerías:
Las librerías de Java no tienen solamente el mérito de existir, además están muy bien diseñadas.
Un ejemplo: la clase Object proporciona el método toString( ). Este método es útil especialmente para depurar y se puede/debe redefinar para las clases que se creen. Pues bien, el método toString( ) de la clase Vector llama simplemente a los métodos toString( ) de los objetos que contiene el Vector. Así, el programa siguiente:
import java.util.Vector;
public class trace {
public static void main (String [ ) arg) {
Vector v = new Vector ( );
v.addElement (new AA ("UNO"));
v.addElement (new AA ("DOS"));
v.addElement (new AA ("TRES"));
System.out.println (v);
};
};
class AA {
string nombre;
public AA (string elnombre) {
nombre = elnombre;
};
public string tostring ( ) {
return nombre;
};
};
Una vez se ha compilado y ejecutado se obtendrá: ( un ,dos, tres )
A continuación se clarificarán globalmente y se
darán ejemplos de los diferentes paquetes que están
a disposición, sin entrar en detalles exhaustivos:
El paquete java.applet tiene un apartado dedicado exclusivamente.
Object es la clase madre de todas las clases. Esta se define para poder desarrollar clases tales como vector, hashtable, que permiten ordenar objetos y recuperarlos más tarde. Así, para definir una tabla tal, hay que definir sobre qué se aplica vector, por ejemplo, se aplica pues sobre la clase object, lo que significa que vector es un vector de object. La existencia de esta clase madre permitirá utilizar vector para todo tipo de object.
Los siguientes métodos son muy interesantes:
class ventana {
string nombre ;
int x, y, h, l ;
}
compartirá el atributo nombre con el objeto original.
Esto permite efectuar operaciones sobre la clase del objeto actual,
como:
Esta clase sirve para definir un nuevo modo de cargamento de
clases. El método predeterminado es buscarlas gracias a
las variables de entorno classpath. Gracias a classloader, se
puede cragar dinámicamente las clases a través de
la red.
A pesar de la existencia de todos estos tipos, las clases asociadas
a los tipos elementales cumplen varias funciones:
Esta clase proporciona funciones matemáticas: senos, cosenos
y valor absoluto, que proporciona, esta última un buen
ejemplode sobrecarga porque existen cuatro versiones diferentes
para cada uno de los cuatro tipos numéricos posibles.
Es una clase enteramente static y por ésto no necesita
instanciarse. En ella se da lugar un conjunto de funcionalidades
dispares:
Esta última función sirve para definir la política
general de seguridad en lo que respecta a los accesos de red de
la aplicación.
Servicios prestados:
La llamada al proceso exec( ) devuelve un proceso.
El proceso del tipo Processus, devuelto al padre en la creación
del proceso hijo, autoriza al padre a:
String y StringBuffer, relacionadas con los string que se explican en el apartado de gramática.
Runable, Tread y TreadGroup, detallados en el apartado sobre los threads.
Thowable tratados en las excepciones.
Para más información:
http://www.java.no/docs/api/java.htm
< A HREF="http://www2.baldwinw.edu/java/docs/java.lang.html">
http://www2.baldwinw.edu/java/docs/java.lang.html
Clase que permite la manipulación de conjuntos de bits
(xor, and . . .)
Dictionary permite almacenar objetos y recuperarlos muy rápidamente
mediante una clave.
Sin tablas de hash, se debe almacenar los objetos en una tabla,
y cada vez que se quiera recuperar un objeto por su clave, se
debe recorrer la tabla efectuando comparaciones de clave hasta
que se haya encontrado la deseada.
La tablas de hash proporciona en general un acceso en dos o tres comparaciones.
En principio, se debe redefinir hashCode ( ) y equal ( ) para la clase que sirve de clase. En la práctica, es a menudo un string, clase para la que estos dos métodos están redefinidos. Por lo tanto no se tendrá que hacer en la mayor parte de los casos.
Properties es una tabla de hash que permite almacenar y recuperar string. Esta tabla Properties puede guardarse en un fichero y recuperarse a partir de éste. Si se intenta utilizar una tabla Properties para gestionar algo distinto de string, el lanzamiento de una excepción indicará el error.
La utilización típica de Properties es la gestión de una tablas de variables de entorno accesibles por un objeto Properties devuelto, de modo predetermido, por el sistema.
Los Properties pueden escribirse y recuperarse en un fichero,
lo que proporciona un medio eficaz de gestionar los ficheros de
configuración.
Esta clase y esta interfaz proporcionan mecanismos que a menudo son redesarrollados en los proyectos.
Los observable crean objetos que previenen a los observer cada vez que les llega uno. Los métodos de Observable necesitan especificar como mínimo cómo van a transmitir la observación. Se advierte a Object y también se impone a los objetos observadores implementar la interfaz Observer.
La existencia de este mecanismo:
Sirve, como no, para la manipulación de la fecha.
Clase que permite tomar un número aleatorio entre unos
intervalos.
Esta clase permite dividir una cadena para obtener subcadenas.
Vector permite gestionar listas.
Los Stacks gestionan el concepto de pila.
Enumeration proporciona el concepto llamado a menudo iterador, que permite recorrer una lista de forma rápida.
Por ejemplo, el método ToString ( ) de Vector utiliza una Enumeration para recorrer la lista y construir el String resultante:
// extracto resumido del fuente de Vector.java
Enumeration e = elements ( ) ;
for (int i = 0; i <= max; i++ ) {
String s = e.nextElement ( ).toString ( );
buf.append (s);
}
// que se habr�a podido escribir tambi�n as�:
Enumeration e;
for (e = elements ( ); e. hasMoreElements ( ); ) (
String s = e.nextElement ( ).toString ( );
buf.append (s);
}
// nextElements ( ) "consume" el elemento actual y desplaza
la posici�n actual de
// la enumeraci�n .
Para más información:
http://www.java.no/docs/api/javae.htm
http://www2.baldwinw.edu/java/docs/java.util.html
Las clases que permiten gestionar las salidas son:
Por otra parte, las clases que permiten gestionar las entradas
son las siguientes:
La clase File permite gestionar los nombres de ficheros.
Para abrir un fichero de entrada (o de salida) debemos crear respectivamente un FileInputStream (FileOutputStream) dándole como parámetro un File o un String directamente. Otro tipo de fichero de entrada puede entonces crearse pasando el objeto FileInputStream como parámetro del constructor.
Por ejemplo, véase como se abre un fichero y se cuenta el número de líneas:
FileInputStream tmp = new FileInputStream ("ejemplo.java");
DataInputStream f = new DataInputStream (tmp);
String lActual = null;
int Numlineas = -1;
do {
lActual = f.readLine ( );
Numlineas ++;
}
While (lActual != null);
System.out.print ("NumLineas:");
System.out.println (NumLineas);
A este extracto hay que añadirle una gestión de excepciones para que sea completo. Las excepciones se describen en un apartado dedicado.
StreamToTokenizer permite hacer el análisis léxico de un fichero.
La utilización de RandomAccessFile permite leer y escribir en un fichero de forma no secuencial. Las clases XXXStream descritas anteriormente leen (rspectivamente escriben) en un fichero secuencialmente, ésto quiere decir que no se elije el punto donde hacerse la lectura (escritura), se hace en el punto actual. El RandomAccessFile permite desplazarse en un fichero para leer o esxribir en cualquier punto. Estos métodos se utilizan generalmente para ficheros que permiten una gestión un poco sofisticada de los datos, con técnicas de acceso rápido.
Para más información:
http://www.java.no/docs/api/javac.htm
http://www2.baldwinw.edu/java/docs/java.io.html
Java ofrece un conjunto de clases que permiten utilizar los Uniform
Resource Locator (URL). Un URL es una dirección electrónica
que permite encontrar una información en Internet dando:
Los sockets, mecanismos de comunicación entre procesos,
funcionea ya estén los procesos en la misma máquina
o no. Los procesos intercambian datos a través de una red,
local o remota.
El principio de la utilización de los sockets es del tipo cliente-servido: un proceso servidor decjara aceptar las conexiones de los clientes, y cuando un cliente se presenta, un sokect se crea para establecer el enlace entre los dos. El mecanismo de los sockets no es propio de Java, pero Java proporciona un aimplementación portable, realizadas gracias a las clases ServerSocket y Socket.
Un ejemplo de un servidor y un cliente. El servidor espera las conexiones y, cada vez que un cliente se presenta, le expide una frase "Buenos días, es usted mi iésimo cliente". Al cabo de cuatro clientes, el servidor para su servicio. Al ser un ejemplo largo, se intercalan los comentarios entre el código.
import java.io.* ;
import java.net.* ;
public class servidor {
public static void main ( String [ ] arg ) {
new servidor ( );
}
Los atributos de la clase servidor son un objeto del tipo ServerSocket,
que sirve para esperar las conexiones, y un objeto del tipo Socket
que sirve para gestionar una conexión a la vez.
ServerSocket unSocket; Socket cliente; int numcliente = 0;
La creación del servidor de socket se hace dando un puerto, que es un número arbitrario que describe el tipo de servicio. Así, un número de puerto está asociado a http, otro a ftp, etc. Aquí se da el número 5000, número que el cliente deberá indicar para encontrar el servidor adecuado.
public servidor ( ) {
try {
unSocket = new ServrSocket (5000);
Un bucle para aceptar 4 clientes y después desaparecer:
While (numclientes < 4) {
numclientes ++;
Se espera al próximo cliente; accept ( ) es un arutina qu esólo da la mano cuando un cliente se ha conectado.
cliente = unSocket.accpt ( );
A un objeto Socket se asocian in fichero de entrada y otro de salida; aquí sólo se utiliza el fichero de salida, en el que se escribe el mensaje a enviar la cliente:
PrintStream p = new Print Stream (cliente.getOutoputStream( ));
System.out.println ("Sirvo a mi cliente n�m. "
+ numclientes );
StringBuffer s = new StringBuffer ("Buenos d�as, usted
es mi cliente n�mero ");
s.append (numclientes);
p.println (s.toString( ););
client.close( );
}
System.out.println ("Ya he tenido bastantes clientes por
hoy");
}
el tratamiento de las excepciones es muy reducido en nuestro ejemplo:
catch (Excepction e) {
System.out.println(e.getMessage( ));
e.printStackTrace ( );
};
El programa cliente se conecta a un servidor indicando la dirección
de la máquina y el puerto, es decir, el tipo de servicio
que solicita. En el ejemplo se ponen en comunicación dos
procesos en la misma máquina, por tanto la dirección
de la máquina es la dirección local y el puerto
es el número elegido por el servidor (5000).
import java.io.*;
import java.net.*;
public class cliente {
public static void main (String [ ] arg ){
new cliente;
}
}
InetAddress direccion;
Socket unsocket;
public cliente ( ) {
try {
El objeto InetAddress sirve para para describir la dirección de una máquina ; aquí el objeto es inicializado mediante un método estático de la clase InetAddress:
direccion = InetAddress.getLocalHost ( );
Se crea entonces el Socket indicando la dirección de la máquina remota, en realidad la misma máquina en el ejemplo, y el servidor deseado:
unsocket = new socket (direccion,5000);
Al Socket se le asocia entonces un fichero de entrada para leer el mensaje que va a recibir del servidor:
DataInputStream in = new DataInputStream (unsocket.getInputStream
( ));
System.Out.println (in.readLine ( ));
unsocket.close ( );
}
catch (Exception e) {
System.out.println (e.getMessage( ));
e.printStackTrace ( );
};
Se puede entonces colocar el servidor en una ventana y, simultáneamente, lanzar varias veces el cliente en otra. En la ventana del servidor se debe obtenner lo siguiente.
c:\ProgramasJava\librer�as\socket>java servidor Sirvo a mi cliente n�m. 1 Sirvo a mi cliente n�m. 2 Sirvo a mi cliente n�m. 3 Sirvo a mi cliente n�m. 4 Ya he tenido bastantes clientes por hoy.
Mientras tanto, en la ventana del cliente, se obtendrá:
c:\ProgramasJava\librer�as\socket>java cliente Buenos d�as, usted es mi cliente n�mero 1 c:\ProgramasJava\librer�as\socket>java cliente Buenos d�as, usted es mi cliente n�mero 2 c:\ProgramasJava\librer�as\socket>java cliente Buenos d�as, usted es mi cliente n�mero 3 c:\ProgramasJava\librer�as\socket>java cliente Buenos d�as, usted es mi cliente n�mero 4 c:\ProgramasJava\librer�as\socket>java cliente connect java.net.SocketException: connect at java.net.PlainSocketImpl.connect (PlainSocketImpl.java:107) at java.net.Socket.<init>(Socket.java:124) at java.net.Socket.<init>(Socket.java:100) at client.<init>(client.java:13) at client.main (client.java:6)
El quinto intento para hacerse servir lanza una excepción,
porque el servidor, en este momento, ya se ha ido.
Obsérvese que el cliente como el servidor pueden indiferentemente leer o escribir. Los mecanismos de comunicación pueden ser refinados cambiando la implememntación de los sockets, mediante la utilización de clases abstractas.
Para más información:
http://www.java.no/docs/api/javaf.htm
http://www2.baldwinw.edu/java/docs/java.net.html
El ámbito de la interfaz gráfica es conceptualmente bastante complejo. Dibujar objetos, botones, no es muy complicado a primera vista, pero cuando se le asocian eventos, cuando deben solaparse unos a otros, redibujarse sin errores, la mecánica se convierte en algo bastante sofisticado.
Java proporciona todas las clases que permiten construir una interfaz gráfica. Existen tres paquetes vinculados a la interfaz gráfica; en este apartado no se explican todas las clases que tienen asociadas, pero se da una referencia acerca de dónde obtener información sobre las mismas. Son:
Enlaces a otras páginas, para más información:
java.awt:
http://www.java.no/javaBin/docs/api/javag.htmhttp://www2.baldwinw.edu/java/docs/java.awt.html
java.awt.peer: http://www.java.no/javaBin/docs/api/javal.peer.htm
http://www2.baldwinw.edu/java/docs/java.peer.html
java.awt.image: http://www.java.no/javaBin/docs/api/javak.htm
Advanced Applets and the AWT: http://www.iconcomp.com/papers/advanced-awt/sld001.htm
Las clases más importantes se describen a continuación.
Esta es la jerarquía de objetos gráficos principales:
COMPONENT, CONTAINER

La clase madre de la mayor parte de las clases gráficas es la clase Component.
Heredan de esta clase:
La clase Container describe los elementos gráficos compuestos de otros elementos gráficos. Son principalmente de dos tipos:
Estos objetos Container tienen un LayoutManager que está asociado y que define la maner cómo van a repartirse los objetos en su interior. LayoutManager es una interfaz de al que se proporcionan varias implementaciones de manera estándar en la librería:
Para añadir un Component en un Container se pueden utilizar los métodos siguientes:
Cuando añade un Component en un Container, el LayoutManager es advertido. Pero algunos LayoutManager necesitan un parámetro suplementario para saber dónde se ubicará el Component. Por ejemplo, BorderLayout espera como parámetro String: "North", "West", "East", "South" o "Center". El parámetro String no está destinado al Container, sino a su LayoutManager.
Dos puntos importantes para empezar:
Así, el programa siguiente:
import java.awt,*;
class falso {
static public void main (String arg [ ) {
window w = new Frame ("Ejemplo");
// Frame es una ventana normal
w.add (new Label ("UNO"));
w.add ("Center", new Label ("DOS"));
w.add ("Algo", new Label ("TRES"));
w.show ( );
w.pack ( );
}
}
sólo hace aparecer una de las tres etiquetas, porque las otras dos han sido añadidas sin parámetro String o con un parámetro incorrecto:
Se observa que una ventana no aparece en su creación, hay que hacerla aparecer explícitamente con el método show( ); y darle un tamaño normal con el método pack( ). Esto permite esperar a la construcción completa de todos los elementos que la componen antes de mostrarla. Si estos dos métodos fueran llamados por el constructor, se vería como se muestra una ventana vacía, y los objetos se irían añadiendo a medida que se construyeran.
Volviendo al LayoutManager: el BorderLayout es algo curioso, que obliga a precisar explícitamente South o North. También se puede utilizar otro LayoutManager, por ejemplo un FlowLayout.
Ejemplo, añadiendo la línea siguiente:
Window w = new Frame ("Ejemplo");
w.setLayout (new FlowLayout ( ));
w.add (new Label ("UNO"));
el resultado es:
El FlowLayout ha recibido los parámetros String del método add( ) cuando existían, pero de todos modos no los tiene en cuenta.
Para combinar varios LayoutManager en diferentes lugares de la Window hay que utilizar la clase Panel. Se pueden colocar varios Panel en una Window. Los Panel se reparten según el LayoutManager de la ventana principal, pero cada Panel tiene su LayoutManager, y éste es el que tiene mayor autoridad en el interior del Panel.
Entonces se pueden repartir los Component en el interior de los Panel.
Si se quisiera realizar una ventana con tres capas superpuestas de botones, cada capa no tiene por qué tener el mismo número de botones.
Se reparten tres Panel en una Window. Cada uno de ellos utiliza un LayoutManager del tipo FlowLayout, y la ventana principal utiliza su BorderLayout estándar.
El programa siguiente:
import java.awt.*;
class usepanel {
public static void main (String arg [ ]){
Window w= new Frame ("3 paneles");
Panel p1 = new Panel ( );
p1.setLayout (new FlowLayout ( ));
p1.add (newLabel ("P1 : 1"));
p1.add (new Label ("P1 : 2"));
p1.add(new Label ("P1 : 3"));
w.add ("North", p1);
Panel p2 = new Panel ( );
p2.setLayout (new FlowLayout ( ));
p2.add (newLabel ("P2 : 1"));
p2.add (new Label ("P2 : 2"));
w.add("Center", p2);
Panel p3 = new Panel ( );
p3.setLayout (new FlowLayout ( ));
p3.add (newLabel ("P3 : 1"));
p3.add (new Label ("P3 : 2"));
p3.add(new Label ("P3 : 3"));
p3.add (new Label ("P3 : 4"));
w.add ("South",p3);
w.show ( );
w.pack ( );
}
}
Visualiza la ventana siguiente:

Finalmente se presenta una ventana gráfica en la que cada componente
elemental indica su tipo:

El único anónimo es la Scrollbar (a la derecha de la lista).
Falta también en la lista Canvas. Esta clase debe redefinirse en la aplicación creada si se quiere dibujar. Se hereda de Canvas y se utiliza un objeto de la clase Graphics para trazar los trazos, rellenar óvalos, etc. Esta clase Graphics es abstracta, por lo que no se puede crear un objeto Graphics para cumplir esta tarea. Por el contrario, es posible solicitar a un objeto gráfico que dé su Graphics asociado a fin de efectuar los dibujos. El método getGraphics( ) devuelve null si el objeto no está en pantalla. Ejemplo:
import java.awt.*;
public class PruebaCanvas {
public static void main (String arg [ ]){
Frame W = new Frame ("Prueba Canvas");
Canvas c = new UnEjemplo ( );
c.resize (new Dimension (200, 200));
w.add ("Center", c);
w.resize (150,150);
w.show( );
c.paint (c.getGraphics ( ));
/* w.getGraphics ( ) habr�a devuelto el mismo objeto*/
}
}
class UnEjemplo extends Canvas {
public void paint (Graphics g) {
g.fillOval (50, 10, 5, 5);
g.drawString ("50x10", 57, 16);
g.fillOval (10, 50, 5, 5);
g.drawString ("10x50", 17, 56);
g.drawRect (10, 60, 100, 30);
g.drawString ("Rect�ngulo", 11, 70);
g.drawString ("Posici�n: 10x60", 11, 80);
g.drawString ("Dimension: 100x30", 11, 90);
}
}
Este ejemplo mostrará la ventana siguiente:

Los eventos son tratados por el método handleEvent de la clase Component. El objeto sobre el cual interviene el evento físicamente es aquél sobre el que se llama ese método.
Si el método handleEvent del objeto devuelve false, el evento debe ser tratado nuevamente por el objeto padre (en el sentido gráfico), que eventualmente lo devolverá a su propio padre, etc. De modo predeterminado, el método handleEvent ( ) de la clase Component devuelve false para señalar que no ha tratado el evento.
En el siguiente ejemplo un Frame contiene un Panel que contiene un Button. Se pone en marcha para cada uno de ellos un método handleEvent( ), el cual se limita a escribir en la salida estándar.
import java.awt.*;
class hevent {
static public void main (String arg [ ]) {
Window w = new Frame2 ( );
w.add ("Center", new Panel ( ));
w.show ( );
w.pack ( );
}
}
class Frame2 extends Frame {
public boolean handleEvent (Event e) {
System.out.println ("Window2 trata el evento");
return false;
}
}
class Panel2 extends Panel {
Panel2 ( ) {
add("Center", new Button2( ));
}
public boolean handleEvent (Event e) {
System.out.println ("Panel2 trata el evento");
return false;
}
}
class Button2 extends Button {
public Button2 ( ) {
super ("�Era necesario pulsar?");
}
public boolean handleEvent (Event e) {
System.out.println ("Button2 trata el evento");
return false;
}
}
Este programa hace aparecer la ventana siguiente:

Un clic sobre el botón entraña entonces el rastro siguiente:
Button2 trata el evento
Panel2 trata el evento
Window2 trata el evento
Si ahora devuelve true en el método handleEvent (Event e) de la clase Button2, el evento no remonta ya la jerarquía de objetos gráficos, porque se considera como tratado por Button2.
El nuevo código del método HandleEvent( ) de Button2:
public boolean handleEvent (Event e) {
System.out.println ("Button2 trata el evento");
return true;
}
El programa muestra ahora
Button2 trata el evento
en el momento en que pulse el botón.
Así puede tratar el evento donde prefiera en la jerarquía gráfica de los objetos. Puede gestionar eventos de forma centralizada, o gestionarlos descentralizando la acción en cada objeto gráfico, o incluso ambas posibilidades a la vez.
Además, el parámetro Event del método handleEvent( ) puede dar:
Este último atributo se utiliza a menudo con el operador instanceof.
También hay que señalar que el método handleEvent( ) de la clase Component llama a losmétodos siguientes: mouseEnter( ), mouseExit( ), mouseMove( ), mouseDown( ), mouseDrag( ), mouseUp( ), KeyDown( ), KeyUp( ), action( ), gotFocus( ), lostFocus( ). Estos métodos corresponden a los eventos más generales de los objetos gráficos.
Además, si se define una clase que hereda de Component, se puede elegir redefinir uno o más de estos métodos en lugar de redefinir handleEvent( ).
La construcción de un prototipo de interfaz de usuario. La aplicación le sirve a un transportista para indicar los horarios para ir de un destino a otro.
El usuario debe introducir tres datos.
El día de salida se proporciona bajo la forma DD/MM/AA, pero para acelerar la edición de los casos más frecuentes, un botón <<hoy>> y un botón <<mañana>> permiten mostrar estas dos fechas directamente en el campo de edición.
La clase DiaPartida que gestiona esta parte de la interfaz gráfica será:
class DiaPartida extends Panel {
TextField dia;
Button diasiguiente;
DiaPartida ( ) {
setLayout (new GridLayout (4,1));
dia = new TextField ( );
hoy = new Button ("Hoy");
diasiguiente = new Button ("Ma�ana");
add (new Label ("D�a salida: "));
add (dia);
add (hoy);
add (diasiguiente);
}
public boolean handleEvent (Event e){
if (e.target == hoy) {
String fechaDeHoy;
//...
//c�lculo de la fecha de hoy
//...
dia.setText (fechaDeHoy);
return false;
}
else if(e.target == diasiguiente) {
//...algo parecido
}
else {
return false;
}
}
};
Utilizado sólo en una ventana, DiaPartida se parece a esto:

Se puede entrar la fecha a mano o bien pulsar uno de los dos botones para que rellene el campo de edición automáticamente.
También hay que hacer editar a usuario la población de partida. Para ello se crea otro Panel, con un texto indicando al usuario que escoja de una lista, y la lista de poblaciones:
class SelectPoblacion extends Panel {
List listaPoblaciones;
SelecPoblacion (String salidaOLlegada) {
setLayout (new BorderLayout (20,20));
StringBuffer titulo = new StringBuffer ( );
titulo.append ("Seleccione su poblaci�n");
titulo.append (salidaOLlegada);
titulo.append (" ");
listaPoblaciones = new List (5, false);
listaPoblaciones.addItem ("Tarragona");
//otras poblaciones ...
listaPoblaciones.addItem ("Oviedo");
add ("North", new Label (titulo.toString( )));
add ("Center", listaPoblaciones);
}
}
Este Panel que permite seleccionar la población de salida quedaría así:

Otro panel idéntico a éste permitirá seleccionar la población de llegada.
Ahora la ventana principal incluye tres paneles:
Se añade un botón cuya función es:
El botón es un atributo de la ventana principal:
button buscar;
y se añade en el momento de la creación de la ventana:
buscar = new Button ("Su viaje: ");
add ("South", buscar);
Por otra parte, el constructor de la ventana principal tiene el aspecto siguiente:
VenPrincipal ( ) {
super = ("Reserva");
buscar = new Button ("Su viaje: ");
salida = new SelecPoblacion ("Salida");
llegada = new SelecPoblacion ("Llegada");
cuando = new DiaSalida( );
setLayout (new BorderLayout (10, 10));
add ("East", llgada);
add ("Center", salida);
add ("West", cuando);
add ("South", buscar);
pack ( );
show ( );
}
En la ventana principal, la gestión de eventos tiene entonces tres funciones:
La función handleEvent( ) de la ventana principal está separada en varias partes que son cada una el objeto de un método:
public boolean handleEvent (Event e) {
// si el usuario quiere salir
if (e.id == Event.Window_Destroy) {
System.exit(0);
}
else if (e.target == buscar) {
// ha pulsado el bot�n para solicitar los horarios
accionBoton ( );
}
else {
//uno de los tres datos dia/salida/llegada ha sido modificado
ActualizaBoton( );
}
return true;
}
void accionBoton ( ) {
if ( (salida.getDescription ( ) == null) ||
(llegada.getDescription( ) == null) ||
(cuando.getDescription ( ) == null) {
//el usuario nno ha encontrado toda la informaci�n
buscar.setLabel ("Su viaje no est� completamente definido");
}
else {
// se crea una nueva ventana con el resultado
new Resultado (this, salida.getDescription ( ),
llegada.getDescription ( ), cuando.getDescription ( ));
}
}
void ActualizaBoton( ) {
StringBuffer b = new StringBuffer ("Su viaje: de ");
if (salida.getDescription ( ) != null) {
b.append (salida.getDescription ( )); }
// ... igual para llegada y cuando ...
buscar.setLabel (b.toString( ));
}
Hay que señalar que hay que añadir al código existente:
La secuencia de utilización es entonces la siguiente. Se elige el día de salida, se elige la población de salida:

después la población de llegada:

Y pulsando sobre el botón recapitulativo inferior, los horarios
solicitados aparecen en una nueva ventana:
