REPÚBLICA BOLIVARIANA DE VENEZUELA MINISTERIO DE EDUCACIÓN SUPERIOR FACULTAD DE INGENIERIA ESCUELA DE ING. ELECTRÓNICA CÁTEDRA DE COMPUTACIÓN V SECCION 255 REALIZADO POR: GÓNGORA, RODRIGO MICHIELI, JORGE NEEF, LABERTO TORO, HOMERO CARACAS, JUNIO DE 2005 CONTROL DE EVENTOS En el pasado, un programa que quisiera saber lo que estaba haciendo el usuario, debía recoger la información él mismo. En la práctica, esto significaba que una vez inicializado, el programa entraba en un gran bucle en el que continuamente se bloqueaba para comprobar que el usuario estuviese haciendo algo interesante (por ejemplo, pulsar un botón, pulsar una tecla, mover una barra o mover el ratón) y tomar las acciones oportunas. Esta técnica se conoce como polling. El polling funciona, pero se vuelve demasiado difícil de manejar con las aplicaciones modernas por dos razones fundamentales: Primero, el uso de polling tiende a colocar todo el código de control de eventos en una única localización (dentro de un gran bucle); Segundo, las interacciones dentro del gran bucle tienden a ser muy complejas. Además, el polling necesita que el programa esté ejecutando el bucle, consumiendo tiempo de CPU, mientras está esperando a que el usuario se decida a hacer algo, lo que supone un gran despilfarro de recursos. El AWT resuelve estos problemas abrazando un paradigma diferente, en el que están basados todos los sistemas modernos de ventanas: la orientación a eventos. Dentro del AWT, todas las acciones que pueda realizar el usuario caen dentro de un gran saco que son los eventos. Un evento describe, con suficiente detalle, una acción particular del usuario. En lugar de que el programa activamente recoja todos los eventos generados por el usuario, el sistema Java avisa al programa cuando se produce un evento interesante. La Clase Event Un contenedor soltado en un entorno gráfico se convierte en rápido receptor de eventos de todo tipo, singularmente de los relacionados con el movimiento del ratón, pulsaciones de teclas, creación/movimiento/destrucción de partes gráficas y, por último, los referidos a acciones del usuario respecto de componentes (elección de un menú, pulsación de un botón, etc.). La clase Event es el jugador principal en el juego de los eventos. Intenta capturar las características fundamentales de todos los eventos que genera el usuario. Los datos miembro de la clase Event son los que se indican a continuación: 1. id - El tipo de evento que se ha producido 2. target - Componente sobre el que se ha producido el evento 3. x, y - Las coordenadas en donde se ha producido el evento relativo al Componente que actualmente está procesando ese evento. El origen se toma en la esquina superior izquierda del Componente 4. key - Para eventos de teclado, es la tecla que se ha pulsado. Su valor será el valor Unicode del carácter que representa la tecla. Otros valores que puede tomas son los de las teclas especiales como INICIO, FIN, F1, F2, etc. 5. when - Instante en que se ha producido el evento 6. modifiers - La combinación aritmética del estado en que se encuentran las teclas modificadoras Mays, Alt, Ctrl. 7. clickCount - El número de clicks de ratón consecutivos. Sólo tiene importancia en los eventos MOUSE_DOWN 8. arg - Es un argumento dependiente del evento. Para objetos Button, este objeto arg es un objeto String que contiene la etiqueta de texto del botón 9. evt - El siguiente evento en una lista encadenada de eventos Una instancia de la clase Event será creada por el sistema Java cada vez que se genere un evento. Es posible, sin embargo, que un programa cree y envíe eventos a los Componentes a través de su método postEvent(). TIPOS DE EVENTOS Los eventos se catalogan por su naturaleza, que se indicará en el miembro id de su estructura. Los grandes grupos de eventos son: Eventos de Ventana Son los que se generan en respuesta a los cambios de una ventana un frame o un dialogo. WINDOW_DESTROY WINDOW_EXPOSE WINDOW_ICONIFY WINDOW_DEICONIFY WINDOW_MOVED Eventos de Teclado Son generados en respuesta a cuando el usuario pulsa y suelta una tecla mientras un Componente tiene el foco de entrada. KEY_PRESS KEY_RELEASE KEY_ACTION KEY_ACTION_RELEASE Eventos de Ratón Son los eventos generados por acciones sobre el ratón dentro de los límites de un Componente. MOUSE_DOWN MOUSE_UP MOUSE_MOVE MOUSE_ENTER MOUSE_EXIT MOUSE_DRAG Eventos de Barras Son los eventos generados como respuesta a la manipulación de barras de desplazamiento (scrollbars). SCROLL_LINE_UP SCROLL_LINE_DOWN SCROLL_PAGE_UP SCROLL_PAGE_DOWN SCROLL_ABSOLUTE Eventos de Lista Son los eventos generados al seleccionar elementos de una lista. LIST_SELECT LIST_DESELECT Eventos Varios Son los eventos generados en función de diversas acciones. ACTION_EVENT LOAD_FILE SAVE_FILE GOT_FOCUS LOST_FOCUS El applet EventosPrnt.java está diseñado para observar los eventos que se producen sobre él. Cada vez que se genera un evento, el applet responde imprimiendo el evento que ha capturado en la línea de comandos desde donde se ha lanzado el applet. Una vez que se haya compilado el código y cargado el applet en el appletviewer o en un navegador con soporte Java, jugar un poco con el applet. Mover el cursor dentro del applet, picar con el ratón, picar y arrastrar, teclear algo, cambiar el tamaño de la ventana y taparla y destaparla con otra. Las acciones anteriores harán que en la ventana en donde se haya lanzado el appletviewer, o en la consola Java en caso de Netscape, vayan apareciendo los textos que indican los eventos que está recibiendo el applet. Lo cierto es que el uso de System.out.println() en un applet es algo que no debería utilizarse, e incluso puede llegar a no funcionar en algunos sistemas, pero tenía la ventaja de ser la forma más fácil de ver los eventos. No obstante, vamos a reescribir el código del applet utilizando una Lista. Una Lista es una lista de cadenas o Strings definidas en java.awt.List. Crearemos una lista de 25 líneas y no permitiremos selección múltiple, que son los dos parámetros que necesita el constructor del objeto List. El código EventosList.java que se muestra a continuación corresponde al anterior ejemplo un poco modificado. import java.awt.*; import java.applet.Applet; public class EventosList extends Applet { List lista; public void init() { lista = new List( 25,false ); add( lista ); lista.addItem( "Evento init" ); } public void start() { lista.addItem( "Evento start" ); } public void destroy() { lista.addItem( "Evento destroy" ); } public void paint( Graphics g ) { lista.addItem( "Evento paint" ); } public void update( Graphics g ) { lista.addItem( "Evento update" ); } public boolean mouseUp( Event evt,int x, int y ) { lista.addItem( "Evento mouseUp en ("+x+","+y+")" ); return false; } public boolean mouseDown( Event evt,int x, int y ) { lista.addItem( "Evento mouseDown en ("+x+","+y+")" ); return false; } public boolean mouseDrag( Event evt,int x, int y ) { lista.addItem( "Evento mouseDrag en ("+x+","+y+")" ); return false; } public boolean mouseMove( Event evt,int x, int y ) { lista.addItem( "Evento mouseMove en ("+x+","+y+")" ); return false; } public boolean mouseEnter( Event evt,int x, int y ) { lista.addItem( "Evento mouseEnter en ("+x+","+y+")" ); return false; } public boolean mouseExit( Event evt,int x, int y ) { lista.addItem( "Evento mouseExit" ); return false; } public boolean keyDown( Event evt,int x ) { lista.addItem( "Evento keyDown,carácter "+(char)x ); return true; } public void getFocus() { lista.addItem( "Evento getFocus" ); } public void gotFocus() { lista.addItem( "Evento gotFocus" ); } public void lostFocus() { lista.addItem( "Evento lostFocus" ); } } El applet VisorEventos.java muestra los datos que componen cada evento que se produce. Hemos incorporado un botón y una lista, tal como se puede apreciar en la figura, para poder generar diferentes eventos. Moviendo el ratón o actuando sobre los dos Componentes, botón y lista, podemos observar los datos que el sistema Java envía en la recolección de esos eventos GENERACION Y PROPAGACION DE EVENTOS Tomemos el applet, EventosPro.java, que aparece en la figura siguiente. Consta de dos instancias de la clase Button, embebidas dentro de una instancia de la clase Panel. Esta instancia está a su vez embebida dentro de otra instancia de la clase Panel. Esta última instancia de la clase Panel está situada junto a una instancia de la clase TextArea, y ambas están embebidas dentro de una instancia de la clase Applet. La figura siguiente presenta los elementos que conforman este applet en forma de árbol, con el TextArea y Button como hojas y la instancia de Applet como raiz. Cuando un usuario interactúa con el applet, el sistema Java crea una instancia de la clase Event y rellena sus datos, miembro con la información necesaria para describir la acción. Es en ese momento cuando el sistema Java permite al applet controlar el evento. Este control comienza por el Componente que recibe inicialmente el evento (por ejemplo, el botón que ha sido pulsado) y se desplaza hacia arriba en el árbol de Componentes, componente a componente, hasta que alcanza al Contenedor de la raíz del árbol. Durante este camino, cada Componente tiene oportunidad de ignorar el evento o reaccionar ante él en una (o más) de las siguientes maneras: 1. Modificar los datos miembros de la instancia de Event 2. Entrar en acción y realizar cálculos basados en la información contenida en el evento 3. Indicar al sistema Java que el evento no debería propagarse más arriba en el árbol El sistema Java pasa información del evento a un Componente a través del método handleEvent() del Componente. Todos los métodos handleEvent() deben ser de la forma: public boolean handleEvent( Event evt ) Un controlador de eventos solamente necesita una información: una referencia a la instancia de la clase Event que contiene la información del evento que se ha producido. El valor devuelto por el método handleEvent() es importante. Indica al sistema Java si el evento ha sido o no completamente controlado por el controlador. Un valor true indica que el evento ha sido controlado y que su propagación debe detenerse. Un valor false indica que el evento ha sido ignorado, o que no ha sido controlado en su totalidad y debe continuar su propagación hacia arriba en el árbol de Componentes. Veamos la descripción de una acción con el applet de la figura anterior. El usuario pulsa el botón "Uno". El sistema run-time del lenguaje Java capturará la información sobre el evento (el número de clicks, la localización del click, la hora en que se ha producido la pulsación y el Componente que ha recibido el click) y empaqueta todos esos datos en una instancia de la clase Event. El sistema Java comienza entonces por el Componente que ha sido pulsado (en este caso, el botón "Uno") y, a través de una llamada al método handleEvent() del Componente, ofrece a éste la posibilidad de reaccionar ante el evento. Si el Componente no controla el evento, o no lo hace completamente (indicado por un valor de retorno false), el sistema Java presentará la instancia de Event al siguiente Componente por encima en el árbol (en este caso, una instancia de la clase Panel). El sistema Java continúa de este mismo modo hasta que el evento es controlado en su totalidad o ya no hay Componentes a los que informar. En la figura siguiente mostramos el camino recorrido por el evento en su intento de que algún Componente lo controle. Cada Componente del applet añade una línea al objeto TextArea indicando que ha recibido un evento. Luego permite que el evento se propague al siguiente Componente. El código del controlador de eventos usado en el ejemplo es el que muestran las siguientes líneas: public boolean handleEvent( Event evt) { if( evt.id == Event.ACTION_EVENT ) ta.appendText( "Panel " + str + " recibe action...\n" ); else if( evt.id == Event.MOUSE_DOWN ) ta.appendText( "Panel " + str + " recibe mouse_down...\n" ); return super.handleEvent( evt ); } METODOS DE CONTROL DE EVENTOS El método handleEvent() es un lugar para que el programador pueda insertar código para controlar los eventos. A veces, sin embargo, un Componente solamente estará interesado en eventos de un cierto tipo (por ejemplo, eventos del ratón). En estos casos, el programador puede colocar el código en un método de ayuda, en lugar de colocarlo en el método handleEvent(). No hay métodos de ayuda para ciertos tipos de eventos, aquí está la lista de los que están disponibles para los programadores: action( Event evt,Object obj ) gotFocus( Event evt,Object obj ) lostFocus( Event evt,Object obj ) mouseEnter( Event evt,int x,int y ) mouseExit( Event evt,int x,int y ) mouseMove( Event evt,int x,int y ) mouseUp( Event evt,int x,int y ) mouseDown( Event evt,int x,int y ) mouseDrag( Event evt,int x,int y ) keyDown( Event evt,int key ) keyUp( Event evt,int key ) (false indicará que el método de ayuda no maneja el evento) La implementación del método handleEvent() proporcionada por la clase Component invoca a cada método de ayuda. Por esta razón, es importante que las implementaciones redefinidas del método handleEvent() en clases derivadas, siempre finalicen con la sentencia: return( super.handleEvent( evt ) ); El siguiente trozo de código ilustra esta regla public boolean handleEvent( Event evt ) { if( evt.target instanceof MiBoton ) { // Hace algo... return true; } return( super.handleEvent( evt ) ); } No seguir esta regla tan simple hará que no se invoquen adecuadamente los métodos de ayuda. El applet EventosRaton.java, que controla los eventos de ratón exclusivamente a través de código insertado en sus métodos de ayuda; va dibujando una línea (rubber band) entre el último punto donde se ha producido un click de ratón y la posición actual del cursor. ACTION_EVENT Algunos de los eventos que más frecuentemente tendremos que controlar son los siguientes: ACTION_EVENT MOUSE_DOWN KEY_PRESS WINDOW_DESTROY En la documentación de la clase Event se encuentra toda la lista de eventos que cualquier aplicación puede necesitar manejar y su documentación; como ejemplo de uso vamos a detenernos en el primero de ellos, ACTION_EVENT. Como ejemplo del manejo de eventos vamos a ver este evento que se provoca al pulsar un botón, seleccionar un menú, etc. Para su control podemos manejarlo en el método handleEvent() o en el método action(). Los dos métodos anteriores pertenecen a la clase Component por lo que todas las clases derivadas de ésta contendrán estos dos métodos y se pueden sobrecargar para que se ajuste su funcionamiento a lo que requiere nuestra aplicación. Veamos el siguiente ejemplo, en que se controla este evento a través del método handleEvent(), que es el método general de manejo de eventos: public boolean handleEvent( Event evt ) { switch( evt.id ) { case Event.ACTION_EVENT: // evt.arg contiene la etiqueta del botón pulsado // o el item del menú que se ha seleccionado if( ( "Pulsado "+n+" veces" ).equals( evt.arg ) ) return( true ); default: return( false ); } } Pero en este caso, cuando se produce este evento se llama al método action(), que sería: public boolean action( Event evt,Object arg ) { if( ( "Pulsado "+n+" veces" ).equals( arg ) ) return( true ); return( false ); } Como se puede comprobar, incluso si las etiquetas cambian se puede recibir el evento. Los ejemplos anteriores corresponden al control de un evento producido por un botón que cambia su etiqueta cada vez que se pulsa. Aunque esta no es la única forma de manejar eventos; de hecho se puede hacer: if( evt.target == miBoton ), en donde se comparan objetos en lugar de etiquetas. EL VISOR DE APPLETS DE SUN El visualizador de applets (appletviewer) es una aplicación que permite ver en funcionamiento applets, sin necesidad de la utilización de un navegador World-Wide-Web como HotJava, Microsoft Explorer o Nescape. Applet La definición más extendida de applet, muy bien resumida por Patrick Naughton, indica que un applet es "una pequeña aplicación accesible en un servidor Internet, que se transporta por la red, se instala automáticamente y se ejecuta in situ como parte de un documento web". Claro que así la definición establece el entorno (Internet, Web, etc.). En realidad, un applet es una aplicación pretendidamente corta (nada impide que ocupe más de un gigabyte, a no ser el pensamiento de que se va a transportar por la red y una mente sensata) basada en un formato gráfico sin representación independiente: es decir, se trata de un elemento a embeber en otras aplicaciones; es un componente en su sentido estricto. Un ejemplo en otro ámbito de cosas podría ser el siguiente: Imaginemos una empresa, que cansada de empezar siempre a codificar desde cero, diseña un formulario con los datos básicos de una persona (nombre, dirección, etc.). Tal formulario no es un diálogo por sí mismo, pero se podría integrar en diálogos de clientes, proveedores, empleados, etc. El hecho de que se integre estática (embebido en un ejecutable) o dinámicamente (intérpretes, DLLs, etc.) no afecta en absoluto a la esencia de su comportamiento como componente con que construir diálogos con sentido autónomo. Pues bien, así es un applet. Lo que ocurre es que, dado que no existe una base adecuada para soportar aplicaciones industriales Java en las que insertar nuestras miniaplicaciones (aunque todo se andará), los applets se han construido mayoritariamente, y con gran acierto comercial (parece), como pequeñas aplicaciones interactivas, con movimiento, luces y sonido... en Internet. Llamadas a Applets con appletviewer Un applet es una mínima aplicación Java diseñada para ejecutarse en un navegador Web. Por tanto, no necesita preocuparse por un método main() ni en dónde se realizan las llamadas. El applet asume que el código se está ejecutando desde dentro de un navegador. El appletviewer se asemeja al mínimo navegador. Espera como argumento el nombre del fichero html que debe cargar, no se le puede pasar directamente un programa Java. Este fichero html debe contener una marca que especifica el código que cargará el appletviewer: <HTML> <APPLET CODE=HolaMundo.class WIDTH=300 HEIGHT=100> </APPLET> </HTML> El appletviewer crear un espacio de navegación, incluyendo un área gráfica, donde se ejecutará el applet, entonces llamará a la clase applet apropiada. En el ejemplo anterior, el appletviewer cargará una clase de nombre HolaMundo y le permitirá trabajar en su espacio gráfico. ARQUITECTURA DE APPLETVIEWER El appletviewer representa el mínimo interfaz de navegación. En la figura se muestran los pasos que seguiría appletviewer para presentarnos el resultado de la ejecución del código de nuestra clase. Esta es una visión simplificada del appletviewer. La función principal de esta aplicación es proporcionar al usuario un objeto de tipo Graphics sobre el que dibujar, y varias funciones para facilitar el uso del objeto Graphics. Ciclo de vida de un Applet Cuando un applet se carga en el appletviewer, comienza su ciclo de vida, que pasaría por las siguientes fases: Se crea una instancia de la clase que controla el applet. En el ejemplo de la figura anterior, sería la clase HolaMundo. El applet se incializa. El applet comienza a ejecutarse. El applet empieza a recibir llamadas. Primero recibe una llamada init (inicializar), seguida de un mensaje start (empezar) y paint (pintar). Estas llamadas pueden ser recibidas asíncronamente. METODOS DE APPLETVIEWER Vamos a utilizar como excusa la función asociada al appletviewer de los siguientes métodos para adentrarnos en su presentación, aunque a lo largo de secciones posteriores, volveremos a referirnos a ellos, porque también son los métodos propios de la clase Applet. init() El método init() se llama cada vez que el appletviewer carga por primera vez la clase. Si el applet llamado no lo sobrecarga, init() no hace nada. Fundamentalmente en este método se debe fijar el tamaño del applet, aunque en el caso de Netscape el tamaño que vale es el que se indique en la línea del fichero html que cargue el applet. También se deben realizar en este método las cargas de imágenes y sonidos necesarios para la ejecución del applet. Y, por supuesto, la asignación de valores a las variables globales a la clase que se utilicen. En el caso de los applet, este método únicamente es llamado por el sistema al cargar el applet. start() start() es la llamada para arrancar el applet cada vez que es visitado. La clase Applet no hace nada en este método. Las clases derivadas deben sobrecargarlo para comenzar la animación, el sonido, etc. Esta función es llamada automáticamente cada vez que la zona de visualización en que está ubicado el applet se expone a la visión, a fin de optimizar en uso de los recursos del sistema y no ejecutar algo que no puede ser apreciado (aunque el programador puede variar este comportamiento y hacer que un applet siga activo aun cuando esté fuera del área de visión). Esto es, imaginemos que cargamos un applet en un navegador minimizado; el sistema llamará al método init(), pero no a start(), que sí será llamado cuando restauremos el navegador a un tamaño que permita ver el applet. Naturalmente, start() se puede ejecutar varias veces: la primera tras init() y las siguientes (porque init() se ejecuta solamente una vez) tras haber aplicado el método stop(). stop() stop() es la llamada para detener la ejecución del applet. Se llama cuando el applet desaparece de la pantalla. La clase Applet tampoco hace nada en este método, que debería ser sobrecargado por las clases derivadas para detener la animación, el sonido, etc. Esta función es llamada cuando el navegador no incluye en su campo de visión al applet; por ejemplo, cuando abandona la página en que está insertado, de forma que el programador puede paralizar los threads que no resulten necesarios respecto de un applet no visible, y luego recuperar su actividad mediante el método start(). destroy() El método destroy() se llama cuando ya no se va a utilizar más el applet, cuando se necesita que sean liberados todos los recursos dispuestos por el applet, por ejemplo, cuando se cierra el navegador. La clase Applet no hace nada en este método. Las clases derivadas deberían sobrecargarlo para hacer una limpieza final. Los applet multithread deberían utilizar destroy() para detener los threads que quedasen activos. El appletviewer también contiene la clase Component (componente), que usa dos métodos para ayudas al applet a escribir en el espacio gráfico que el appletviewer le proporciona para su ejecución. paint( Graphics g ) Es la función llamada cada vez que el área de dibujo del applet necesita ser refrescada. La clase Applet simplemente dibuja un rectángulo gris en el área, es la clase derivada, obviamente, la que debería sobrecargar este método para representar algo inteligente en la pantalla. Cada vez que la zona del applet es cubierta por otra ventana, se desplaza el applet fuera de la visión o el applet cambia de posición debido a un redimensionamiento del navegador, el sistema llama automáticamente a este método, pasando como argumento un objeto de tipo Graphics que delimita la zona a ser pintada; en realidad se pasa una referencia al contexto gráfico en uso, y que representa la ventana del applet en la página web. update( Graphics g ) Esta es la función que realmente se llama cuando se necesita una actualización de la pantalla. La clase Applet simplemente limpia el área y llama al método paint(). Esta funcionalidad es suficiente para la mayoría de los casos; aunque, de cualquier forma, las clases derivadas pueden sustituir esta funcionalidad para sus propósitos especiales. Es decir, en las situaciones detalladas anteriormente que dañan la zona de exposición del applet, el sistema llama al método paint(), pero en realidad la llamada se realiza al método update(), cuyo comportamiento establecido en la clase Component es llamar al método paint(), tras haber rellenado la zona del applet con su color de fondo por defecto. Pudiera parecer así que se trata de un método de efecto neutro, pero si la función paint() cambiara el color del fondo, podríamos percibir un flick de cambio de colores nada agradable. Por tanto, habrá que cuidarse por lo común, de eliminar este efecto de limpia primero, sobrecargando el método update(), para que llame únicamente a paint(). Otra solución sería insertar el código de pintado en una sobrecarga del método update() y escribir un método paint() que sólo llame a update(). La última solución pasaría por usar el mismo método setBackground( Color ), en el método init() para así evitar el efecto visual sin tener que sobrecargar el método update(). Estas son las mismas razones que aconsejan usar el método resize() inserto en init(), para evitar el mismo desagradable efecto. repaint Llamando a este método se podrá forzar la actualización de un applet, la llamada a update(). Pero hay que tener cierto cuidado, porque AWT posee cierta inteligencia (combinación casi siempre nefasta), de forma que si se llama a update() mediante repaint() con una frecuencia muy corta, AWT ignorará las llamadas a update() que estime oportuno, pues considera a esta función como un bien escaso. Sinopsis La llamada a appletviewer es de la forma: appletviewer [-debug] urls... El appletviewer toma como parámetro de ejecución, o bien el nombre del un fichero html conteniendo el tag (marca) <APPLET>, o bien un URL hacia un fichero HTML que contenga esa marca. Si el fichero html no contiene un tag <APPLET> válido, el appletviewer no hará nada. El appletviewer no muestra otras marcas html. La única opción válida que admite la llamada a appletviewer es -debug, que arranca el applet en el depurador de Java, jdb. Para poder ver el código fuente en el depurador, se tiene que compilar el fichero .java con la opción -g. Ejemplo de uso En el ejemplo de llamada al appletviewer siguiente, hacemos que se ejecute el applet básico que crearemos en la sección siguiente y que lanzaremos desde un fichero html del mismo nombre que nuestro fichero de código fuente Java. %appletviewer HolaMundo.html Esta llamada lanzaría la ejecución de HolaMundo.class appletviewer, abriéndose en pantalla la ventana siguiente: en el FUNCIONES DE MENU DE APPLETVIEWER El appletviewer tiene un único menú mostrado en la imagen siguiente y que vamos a explicar en cada una de sus opciones, ya que lo usaremos a menudo cuando vayamos avanzando en nuestros conocimientos de Java. Restart La función Restart llama al método stop() y seguidamente llama de nuevo a start(), que es el método que ha lanzado inicialmente la ejecución del applet. Se puede utilizar Restart para simular el movimiento entre páginas en un documento html. Reload La función Reload llama al método stop() y luego al método destroy() en el applet actual. A continuación carga una nueva copia del applet y la arranca llamando al método start(). Clone La función Clone crea una copia del applet actual en una ventana de appletviewer nueva. En realidad es un appletviewer idéntico con el mismo URL. Tag La función Tag muestra en una ventana hija del appletviewer el código html cargado para su ejecución. Es similar a la función View Source que figura en la mayoría de los navegadores, Netscape, Internet Explorer y HotJava incluidos. Info La función Info lee los comentarios de documentación contenidos en el fichero html y muestra la información de los parámetros (si la hay). Properties El appletviewer tiene las funciones básicas de presentación de un navegador y la función Properties (propiedades de la red) permite cambiar o establecer el modo de seguridad o fijar los servidores de proxy o firewall. Close La función Close llama al método destroy() de la ventana actual del appletviewer, teminando su ejecución. Quit La función Quit llama al método destroy() de cada una de las copias del appletviewer que se encuentren lanzadas, concluyendo la ejecución de todas ellas y terminando entonces el appletviewer. UN APPLET BASICO EN JAVA Vamos a comenzar la creación del código fuente del un applet que satisfaga nuestras necesidades. Recordamos que Java utiliza la extensión .java para designar los ficheros fuente. HolaMundo A continuación está el código fuente del applet HolaMundo, que es la versión applet de la mínima aplicación Java que antes habíamos escrito. Guardar este código en un fichero fuente Java como HolaMundo.java. // // Applet HolaMundo de ejemplo // import java.awt.Graphics; import java.applet.Applet; public class HolaMundo extends Applet { public void paint( Graphics g ) { g.drawString( "Hola Mundo!",25,25 ) ; } } Componentes básicos de un Applet El lenguaje Java implementa un modelo de Programación Orientada a Objetos. Los objetos sirven de bloques centrales de construcción de los programas Java. De la misma forma que otros lenguajes de programación, Java tiene variables de estado y métodos. Veamos como se descompone un applet en sus piezas/objetos: /* Sección de importaciones */ public class NombreDelNuevoApplet extends Applet { /* Aquí se declaran las variables de estado (public y private) */ /* Los métodos para la interacción con los objetos se declaran y definen aquí */ public void MetodoUno( parámetros ) { /* Aquí viene para cada método, el código Java que desempeña la tarea. Qué código se use depende del applet */ } } Para HolaMundo, se importan las dos clases que necesita. No hay variables de estado, y sólo se tiene que definir un método para que el applet tenga el comportamiento esperado. Clases incluidas El comando import carga otras clases dentro de nuestro código fuente. El importar una clase desde un paquete de Java hace que esa clase importada esté disponible para todo el código incluido en el fichero fuente Java que la importa. Por ejemplo, en el applet HolaMundo se importa la clase java.awt.Graphics, y podremos llamar a los métodos de esta clase desde cualquier método de nuestro programa que se encuentre en el fichero HolaMundo.java. Esta clase define una área gráfica y métodos para poder dibujar dentro de ella. La función paint() declara a g como un objeto de tipo Graphics; luego, paint() usa el método drawString() de la clase Graphics para generar su salida. La clase Applet Se puede crear una nueva clase, en este caso HolaMundo, extendiendo la clase básica de Java: Applet. De esta forma, se hereda todo lo necesario para crear un applet. Modificando determinados métodos del applet, podemos lograr que lleve a cabo las funciones que deseamos. import java.applet.Applet; . . . public class HolaMundo extends Applet { Métodos de Applet La parte del applet a modificar es el método paint(). En la clase Applet, se llama al método paint() cada vez que el método arranca o necesita ser refrescado, pero no hace nada. En nuestro caso, lo que hacemos es: public void paint( Graphics g ) { g.drawString( "Hola Mundo!",25,25 ); } De acuerdo a las normas de sobrecarga, se ejecutará este último paint() y no el paint() vacío de la clase Applet. Luego, aquí se ejecuta el método drawString(), que le dice al applet cómo debe aparecer un texto en el área de dibujo. Otros métodos básicos para dibujar son: drawLine( int x1,int y1,int x2,int y2 ) drawRect( int x,int y,int ancho,int alto ) drawOval( int x,int y,int ancho,int alto ) Tanto para drawRect() como para drawOval(), las coordenadas (x,y) son la esquina superior izquierda del rectángulo (para drawOval, el óvalo es encajado en el rectángulo que lo circunscribe). COMPILACION DE UN APPLET Ahora que tenemos el código de nuestro applet básico y el fichero fuente Java que lo contiene, necesitamos compilarlo y obtener un fichero .class ejecutable. Se utiliza el compilador Java, javac, para realizar la tarea. El comando de compilación será: %javac HolaMundo.java Eso es todo. El compilador javac generará un fichero HolaMundo.class que podrá ser llamado desde cualquier navegador con soporte Java y, por tanto, capaz de ejecutar applets Java. Llamada a Applets ¿Qué tienen de especial HotJava, Microsoft Explorer o Netscape con respecto a otros navegadores? Con ellos se puede ver html básico y acceder a todo el texto, gráfico, sonido e hipertexto que se pueda ver con cualquier otro navegador. Pero además, pueden ejecutar applets, que no es html estándar. Ambos navegadores entienden código html que lleve la marca <APPLET>: <APPLET CODE="SuCodigo.class" WIDTH=100 HEIGHT=50> </APPLET> Esta marca html llama al applet SuCodigo.class y establece su ancho y alto inicial. Cuando se acceda a la página Web donde se encuentre incluida la marca, se ejecutará el byte-code contenido en SuCodigo.class, obteniéndose el resultado de la ejecución del applet en la ventana del navegador, con soporte Java, que estemos utilizando. Prueba de un Applet El JDK, Kit de Desarrollo de Java, incluye el visor de applets básico, appletviewer, que puede utilizarse para la visualización rápida y prueba de nuestros applets, tal como se ha visto ya. La ejecución de un applet sobre appletviewer se realiza a través de la llamada: %appletviewer fichero.html En nuestro caso el fichero con el código html que ejecutará nuestro applet HolaMundo es HolaMundo.html que generará la salida que se mostraba en la sección sobre el de appletviewer. LA MARCA APPLET DE HTML Dado que los applets están mayormente destinados a ejecutarse en navegadores Web, había que preparar el lenguaje HTML para soportar Java, o mejor, los applets. El esquema de marcas de HTML, y la evolución del estándar marcado por Netscape hicieron fácil la adición de una nueva marca que permitiera, una vez añadido el correspondiente código gestor en los navegadores, la ejecución de programas Java en ellos. La sintaxis de las etiquetas <APPLET> y <PARAM> es la que se muestra a continuación y que iremos explicando en párrafos posteriores: <APPLET CODE= WIDTH= HEIGTH= [CODEBASE=] [ALT=] [NAME=] [ALIGN=] [VSPACE=] [HSPACE=]> <PARAM NAME= VALUE= > </APPLET> Atributos obligatorios: CODE : Nombre de la clase principal WIDTH : Anchura inicial HEIGHT : Altura inicial Atributos opcionales: CODEBASE : URL base del applet ALT : Texto alternativo NAME : Nombre de la instancia ALIGN : Justificación del applet VSPACE : Espaciado vertical HSPACE : Espaciado horizontal Los applets se incluyen en las páginas Web a través de la marca <APPLET>, que para quien conozca html resultará muy similar a la marca <IMG>. Ambas necesitan la referencia a un fichero fuente que no forma parte de la página en que se encuentran embebidos. IMG hace esto a través de SRC=parámetro y APPLET lo hace a través CODE=parámetro. El parámetro de CODE indica al navegador dónde se encuentra el fichero con el código Java compilado .class. Es una localización relativa al documento fuente. Por razones que no entiendo muy bien, pero posiblemente relacionadas con los packages y classpaths, si un applet reside en un directorio diferente del que contiene a la página en que se encuentra embebido, entonces no se indica un URL a esta localización, sino que se apunta al directorio del fichero .class utilizando el parámetro CODEBASE, aunque todavía se puede usar CODE para proporcionar el nombre del fichero .class. Al igual que IMG, APPLET tiene una serie de parámetros que lo posicionan en la página. WIDTH y HEIGHT especifican el tamaño del rectángulo que contendrá al applet, se indican en pixels. ALIGN funciona igual que con IMG (en los navegadores que lo soportan), definiendo cómo se posiciona el rectángulo del applet con respecto a los otros elementos de la página. Los valores posibles a especificar son: LEFT, RIGHT, TOP, TEXTTOP, MIDDLE, ABSMIDDLE, BASELINE, BOTTOM y ABSBOTTOM. Y, finalmente, lo mismo que con IMG, se puede especificar un HSPACE y un VSPACE en pixels para indicar la cantidad de espacio vacío que habrá de separación entre el applet y el texto que le rodea. APPLET tiene una marca ALT. La utilizaría un navegador que entendiese la marca APPLET, pero que por alguna razón, no pudiese ejecutarlo. Por ejemplo, si un applet necesita escribir en el disco duro de nuestro ordenador, pero en las características de seguridad tenemos bloqueada esa posibilidad, entonces el navegador presentaría el texto asociado a ALT. ALT no es utilizado por los navegadores que no entienden la marca APPLET, por ello se ha definido la marca </APPLET>, que finaliza la descripción del applet. Un navegador con soporte Java ignorará todo el texto que haya entre las dos marcas <APPLET> y </APPLET>, sin embargo, un navegador que no soporte Java ignorará las marcas y presentará el texto que se encuentre entre ellas. ATRIBUTOS DE APPLET Los atributos que acompañan a la etiqueta <APPLET>, algunos son obligatorios y otros son opcionales. Todos los atributos, siguiendo la sintaxis de html, se especifican de la forma: atributo=valor. Los atributos obligatorios son: CODE Indica el fichero de clase ejecutable, que tiene la extensión .class. No se permite un URL absoluto, como ya se ha dicho, aunque sí puede ser relativo al atributo opcional CODEBASE. WIDTH Indica la anchura inicial que el navegador debe reservar para el applet en pixels. HEIGHT Indica la altura inicial en pixels. Un applet que disponga de una geometría fija no se verá redimensionado por estos atributos. Por ello, si los atributos definen una zona menor que la que el applet utiliza, únicamente se verá parte del mismo, como si se visualiza a través de una ventana, eso sí, sin ningún tipo de desplazamiento. Los atributos opcionales que pueden acompañar a la marca APPLET comprenden los que se indican a continuación: CODEBASE Se emplea para utilizar el URL base del applet. En caso de no especificarse, se utilizará el mismo que tiene el documento. ALT Como ya se ha dicho, funciona exactamente igual que el ALT de la marca <IMG>, es decir, muestra un texto alternativo, en este caso al applet, en navegadores en modo texto o que entiendan la etiqueta APPLET pero no implementen una máquina virtual Java. NAME Otorga un nombre simbólico a esta instancia del applet en la página que puede ser empleado por otros applets de la misma página para localizarlo. Así, un applet puede ser cargado varias veces en la misma página tomando un nombre simbólico distinto en cada momento. ALIGN Se emplea para alinear el applet permitiendo al texto fluir a su alrededor. Puede tomas los siguientes valores: LEFT, RIGHT, TOP, TEXTTOP, MIDDLE, ABSMIDDLE, BASELINE, BOTTOM y ABSBOTTOM. VSPACE Indica el espaciado vertical entre el applet y el texto, en pixels. Sólo funciona cuando se ha indicado ALIGN = LEFT o RIGHT. HSPACE Funciona igual que el anterior pero indicando espaciamiento horizontal, en pixels. Sólo funciona cuando se ha indicado ALIGN = LEFT o RIGHT. Es probable encontrar en algunas distribuciones otras etiquetas para la inclusión de applets, como <APP>. Esto se debe a que estamos ante la tercera revisión de la extensión de HTML para la incrustación de applets y ha sido adoptada como la definitiva. Por ello, cualquier otro medio corresponde a implementaciones obsoletas que han quedado descartadas. PASO DE PARAMETROS A APPLETS El espacio que queda entre las marcas de apertura y cierre de la definición de un applet, se utiliza para el paso de parámetros al applet. Para ello se utiliza la marca PARAM en la página HTML para indicar los parámetros y el método getParameter() de la clase java.applet.Applet para leerlos en el código interno del applet. La construcción puede repetirse cuantas veces se quiera, una tras otra. Los atributos que acompañan a la marca PARAM son los siguientes: NAME Nombre del parámetro que se desea pasar al applet. VALUE Valor que se desea transmitir en el parámetro que se ha indicado antes. Texto HTML Texto HTML que será interpretado por los navegadores que no entienden la marca APPLET en sustitución del applet mismo. Para mostar esta posibilidad vamos a modificar nuestro applet básico HolaMundo para que pueda saludar a cualquiera. Lo que haremos será pasarle al applet el nombre de la persona a quien queremos saludar. Generamos el código para ello y lo guardamos en el fichero HolaTal.java import java.awt.Graphics; import java.applet.Applet; public class HolaTal extends Applet { String nombre; public void init() { nombre = getParameter( "Nombre" ); } public void paint( Graphics g ) { g.drawString( "Hola "+nombre+"!",25,25 ); } } Si compilamos el ejemplo obtendremos el fichero HolaTal.class que incluiremos en nuestra página Web. Vamos a generar el fichero HolaTal.html, en el que incluiremos nuestro applet, y que debería tener el siguiente contenido: <HTML> <APPLET CODE=HolaTal.class WIDTH=300 HEIGHT=100> <PARAM NAME="Nombre" VALUE="Agustin"> </APPLET> </HTML> Por supuesto, que puedes sustituir mi nombre por el tuyo. Este cambio no afectará al código Java, no será necesario recompilarlo para que te salude a ti el applet. Los parámetros no se limitan a uno solo. Se puede pasar al applet cualquier número de parámetros y siempre hay que indicar un nombre y un valor para cada uno de ellos. El método getParameter() es fácil de entender. El único argumento que necesita es el nombre del parámetro cuyo valor queremos recuperar. Todos los parámetros se pasan como Strings, en caso de necesitar pasarle al applet un valor entero, se ha de pasar como String, recuperarlo como tal y luego convertirlo al tipo que deseemos. Tanto el argumento de NAME como el de VALUE deben ir colocados entre dobles comillas (") ya que son String. El hecho de que las marcas <APPLET> y <PARAM> sean ignoradas por los navegadores que no entienden Java, es inteligentemente aprovechado a la hora de definir un contenido alternativo a ser mostrado en este último caso. Así la etiqueta es doble: <APPLET atributos> parámetros contenido alternativo </APPLET> Nuestro fichero para mostrar el applet de ejemplo lo modificaremos para que pueda ser visualizado en cualquier navegador y en unos casos presente la información alternativa y en otros, ejcute nuestro applet: <HTML> <APPLET CODE=HolaTal.class WIDTH=300 HEIGHT=100> <PARAM NAME="Nombre" VALUE="Agustin"> No verás lo bueno hasta que consigas un navegador <I>Java Compatible</I> </APPLET> </HTML> CONCLUSION Para nosotros la realización de este trabajo fue un poco confuso y complicado, debido a que nuestro manejo sobre el tema no es mucho que podamos decir. Con la investigación del tema pudimos comprender de una manera un poco más profunda sobre los Eventos y Applets en el lenguaje JAVA. A pesar de que este lenguaje es nuevo, relativamente, es un lenguaje que está agarrando mucha fuerza en el mundo de la WEB, por lo que es de gran importancia realizar un estudio, del mismo. Los eventos dentro del java nos permiten mantener un control de todas aquellas acciones que ocurren en interacción con las cosas que ocurren dentro del programa basado en java. Los applets, nos permiten crear elementos de forma gráfica, por lo que permiten una mejor interacción con el usuario. Los applets son muy sencillos de usar y nos permiten, a la hora de verlo funcionando, llamar más la atención del usuario por medios gráficos. A pesar de que fue un trabajo complejo, por nuestro escaso dominio del tema, nos pareció muy interesante ya que nos permitió generar conocimientos que no existían en nuestras personas.