notasgui

119
Interfaces Gr´ aficas de Usuario con JAVA ector Tejeda V Febrero, 2010

Upload: stalin-rosero

Post on 24-Oct-2015

55 views

Category:

Documents


6 download

TRANSCRIPT

Page 1: notasGUI

Interfaces Graficas de Usuario con JAVA

Hector Tejeda V

Febrero, 2010

Page 2: notasGUI

2

Page 3: notasGUI

Indice general

1. Introduccion 51.1. Componentes, disenadores y eventos . . . . . . . . . . . . . . 61.2. AWT y Swing . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2. Caso de estudio 92.1. Mostrando texto en un cuadro de dialogo . . . . . . . . . . . . 92.2. Ingresando texto en un cuadro de dialogo . . . . . . . . . . . . 10

2.2.1. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 112.3. Creando dibujos simples . . . . . . . . . . . . . . . . . . . . . 12

2.3.1. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 152.4. Dibujando rectangulos y elipses . . . . . . . . . . . . . . . . . 16

2.4.1. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 182.5. Figuras Rellenas y Colores . . . . . . . . . . . . . . . . . . . . 19

2.5.1. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 212.6. Dibujo de Arcos . . . . . . . . . . . . . . . . . . . . . . . . . . 22

2.6.1. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 242.7. Usando objetos con graficas . . . . . . . . . . . . . . . . . . . 25

2.7.1. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 282.8. Texto e imagenes con etiquetas . . . . . . . . . . . . . . . . . 30

2.8.1. Ejercicio . . . . . . . . . . . . . . . . . . . . . . . . . . 322.9. Dibujado con polimorfismo . . . . . . . . . . . . . . . . . . . . 32

2.9.1. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 32

3. Componentes GUI 353.1. Introduccion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353.2. Generalidades de Componentes Swing . . . . . . . . . . . . . . 353.3. Mostrar texto e imagenes en una ventana . . . . . . . . . . . . 383.4. Campos de texto y eventos . . . . . . . . . . . . . . . . . . . . 42

Page 4: notasGUI

4 INDICE GENERAL

3.5. Tipos de eventos e interfaces receptoras . . . . . . . . . . . . . 493.6. Como trabaja el manejador de eventos . . . . . . . . . . . . . 513.7. JButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533.8. Botones que mantienen estado . . . . . . . . . . . . . . . . . . 56

3.8.1. JCheckBox . . . . . . . . . . . . . . . . . . . . . . . . 573.8.2. JRadioButton . . . . . . . . . . . . . . . . . . . . . . . 60

3.9. JComboBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643.10. JList . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 663.11. Listas de seleccion multiple . . . . . . . . . . . . . . . . . . . 683.12. Manejo de eventos del raton . . . . . . . . . . . . . . . . . . . 713.13. Clases adaptadoras . . . . . . . . . . . . . . . . . . . . . . . . 753.14. Subclase JPanel para dibujar con el raton . . . . . . . . . . . 783.15. Manejo de eventos del teclado . . . . . . . . . . . . . . . . . . 823.16. Manejadores de diseno . . . . . . . . . . . . . . . . . . . . . . 85

3.16.1. FlowLayout . . . . . . . . . . . . . . . . . . . . . . . . 873.16.2. BorderLayout . . . . . . . . . . . . . . . . . . . . . . . 903.16.3. GridLayout . . . . . . . . . . . . . . . . . . . . . . . . 93

3.17. Paneles anidados . . . . . . . . . . . . . . . . . . . . . . . . . 953.18. JTextArea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 973.19. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 993.20. Usando Menus con Frames . . . . . . . . . . . . . . . . . . . . 1003.21. JPopupMenu . . . . . . . . . . . . . . . . . . . . . . . . . . . 1083.22. JTabbedPane . . . . . . . . . . . . . . . . . . . . . . . . . . . 1123.23. Manejador de Diseno: BoxLayout . . . . . . . . . . . . . . . . 114

Page 5: notasGUI

Capıtulo 1

Introduccion

Se presenta en este material, ejemplos que no son considerados en uncurso introductorio de Java, ya que las aplicaciones que se revisan tieneninterfaces de usuario que utilizan exclusivamente texto. La razon por la cualson usadas estas interfaces textuales no es, porque tengan una gran ventaja;en realidad, la unica ventaja que tienen es su facilidad para ser creadas.

Por lo general, en un curso introductorio de Java se pretende no distraermucho la atencion del estudiante en las cuestiones importantes del desarrollode software; por lo que en general la mayorıa de los cursos introductorios secentran en cuestiones relacionadas con la estructura y la interaccion de losobjetos, el diseno de clases y la calidad del codigo.

Las interfaces graficas de usuario o GUI (Graphical User Interface) sontambien construidas usando objetos que interactuan, pero cuentan con unaestructura muy especializada y es por lo anterior que se evita usarlas antes deaprender la estructura de los objetos en terminos mas generales. Una vez quese tienen las bases, se esta preparado para dar una mirada a la construccionde las GUI.

Las GUI completan las aplicaciones con una interfaz formada por venta-nas, menus, botones y otros componentes graficos, y hacen que la aplicaciontenga una apariencia mas parecida a las aplicaciones tıpicas, que son usadaspor la mayorıa de la gente que usa un sistema de computo.

Se debe observar el doble significado de la palabra interfaz. Las interfacesde las que se abordan en este material no son las interfaces de las clasesni la construccion interfaz de Java. Cuando se dice interfaces de usuario,se refiere a la parte de una aplicacion que esta visible en la pantalla y quepermite que un usuario interactue con ella.

Page 6: notasGUI

6 Introduccion

Una vez que se sabe como crear una GUI en Java, se pueden desarrollarprogramas que tengan una mejor presentacion visual.

1.1. Componentes, gestores de disposicion y

captura de eventos

Para la creacion de una GUI son varios los detalles que estan involucrados.En este material no se cubren todos los detalles de las distintas tareas quese pueden hacer, solo se discuten los principios generales y un buen numerode ejemplos.

En Java, toda la programacion de una GUI se hace mediante el uso debibliotecas de clases estandares especializadas. Una vez que se han compren-dido los principios se pueden encontrar todos los detalles necesarios en ladocumentacion de la biblioteca estandar.

Los principios que se necesitan revisar se pueden dividir en tres bloques:

1. Las clases de elementos que se pueden mostrar en la pantalla.

2. La forma como se pueden acomodar los elementos que se muestran enla pantalla.

3. La forma como se debe responder a una entrada del usuario.

Se discuten los puntos anteriores mediante los terminos componentes,gestores de dispositivos y manejo de eventos respectivamente.

Los componentes son las partes individuales con las cuales se construyeuna GUI. Ejemplos de estos son los botones, los menus, los elementos delmenu, las cajas de verificacion, los deslizadores, los campos de texto, etc. Labiblioteca de Java contiene una cantidad de componentes disenados para serusados inmediatamente y tambien es posible que el programador escriba suspropios componentes. Es necesario que se aprenda cuales son los componen-tes importantes, como son creados y como hacer para que aparezcan en lapantalla tal cual se desea verlos.

Los gestores de disposicion son empleados en la ubicacion de los compo-nentes en la pantalla. Los sistemas de GUI mas viejos y primitivos manejabancoordenadas bidimensionales, donde el programador indicaba mediante unpar ordenado de valores, que expresaban un valor en pıxeles, la posicion delcomponente ademas del alto y el ancho del mismo. En los sistemas de GUI

Page 7: notasGUI

1.2 AWT y Swing 7

mas modernos, esta forma es muy simple, ya que se debe tener en cuenta lasdistintas resoluciones de pantalla, las diferentes fuentes, las ventanas que losusuarios pueden redimensionar, y otros aspectos que hacen difıcil la distribu-cion de los componentes. La solucion es un esquema donde el programadorpueda indicar la disposicion de los componentes en terminos mas generales.Por ejemplo, se puede indicar que “este componente debera estar debajo deeste otro” o que “este componente se estrechara cuando la ventana cambiede tamano pero este otro tendra un tamano constante”. Lo anterior se lograusando los gestores de disposicion.

El manejo de eventos se refiere a la tecnica que se usa para respondera las entradas del usuario. Una vez que los componentes han sido creado yque han sido posicionados en la pantalla, es necesario asegurar de que ocurraalgo cuando el usuario presione un boton, por ejemplo. El modelo que usa labiblioteca de Java para lograr lo anterior esta basada en eventos: si un usuarioactiva un componente, por ejemplo, por pulsar un boton o seleccionar unelemento de un menu, el sistema generara un evento. Entonces, la aplicacionpuede recibir una notificacion del evento, mediante la invocacion de uno desus metodos, y se puede llevar a cabo la accion adecuada.

1.2. AWT y Swing

Java tiene dos bibliotecas para la construccion de interfaces graficas deusuario. La mas antigua, denominada AWT (Abstract Window Toolkit), fueintroducida con el primer sistema Java original; mas tarde, se agrego unamejor biblioteca denominada Swing.

Swing utiliza algunas de las clases de la biblioteca AWT, reemplaza algu-nas de las clases de AWT con sus propias versiones y agrega clases nuevas.

En este material, se usara la biblioteca Swing, aunque se usaran algunasde las clases de AWT que todavıa son empleadas en los programas Swing.Para el caso de que existan clases equivalentes en ambas bibliotecas, se usaranlas versiones de Swing.

Como existen clases equivalentes en AWT y en Swing, las versiones Swinghan sido identificadas mediante el agregado de la letra ((J)) al comienzo delnombre de la clase. Por ejemplo, existen las clases de nombre Button yJButton, Frame y JFrame, Menu y JMenu, etc. Las clases que comienzan con((J)) son versiones Swing; y seran las unicas que se usaran.

Page 8: notasGUI

8 Introduccion

Page 9: notasGUI

Capıtulo 2

Caso de estudio

Este caso de estudio esta disenado para iniciar el aprendizaje de las poten-tes capacidades de Java para crear GUIs. Se muestran diez secciones breves,en donde cada seccion introduce unos cuantos conceptos basicos y propor-ciona ejemplos visuales graficos. En las secciones subsecuentes, se empleanconceptos de la programacion orientada a objetos para crear aplicaciones quedibujan una variedad de figuras.

2.1. Mostrando texto en un cuadro de dialo-

go

Muchas aplicaciones usan ventanas o cuadros de dialogo, tambien lla-mados dialogos para mostrar la salida. Por ejemplo, los navegadores comoFirefox o Microsoft Internet Explorer muestran paginas web en su propiaventana. Programas de correo electronico permiten teclear y leer mensajesen una ventana. Tıpicamente, los cuadros de dialogo son ventanas en lascuales los programas muestran mensajes importantes a los usuarios. La cla-se JOptionPane proporciona cuadros de dialogo empaquetados previamenteque permiten a los programas mostrar ventanas conteniendo ventanas —tales ventanas son llamadas dialogos de mensaje. El codigo que se muestra acontinuacion muestra la cadena Bienvenido a Java en tres renglones.

1 // Dialogo1.java

2 // Imprimiendo multiples lıneas en un cuadro de dialogo

3 import javax.swing.JOptionPane; // importar la clase JOptionPane

4

Page 10: notasGUI

10 Caso de estudio

5 public class Dialogo1 {

6 public static void main( String args[] ) {

7 // Mostrar un cuadro de dialogo con un mensaje

8 JOptionPane.showMessageDialog( null, "Bienvenido\na\nJava" );

9 } // fin del main

10 } // fin del cuadro de dialogo

En la lınea 3 se indica que el programa usara la clase JOptionPane del pa-quete javax.swing. Este paquete contiene varias clases que ayudan a crear laGUI para las aplicaciones. Los componentes GUI facilitan la entrada de datospara un usuario, y la presentacion de datos al usuario. La lınea 8 llama almetodo showMessageDialog para mostrar un cuadro de dialogo conteniendoun mensaje. El metodo requiere dos argumentos. El primer argumento de-termina el Frame al cual es asociado el dialogo, si es null se asocia con elFrame por defecto. El segundo argumento es el String que sera mostradoen el dialogo.

El metodo showMessageDialog es un metodo estatico de la clase JOptionPane.Los metodos estaticos definen frecuentemente tareas usadas que no requierenla creacion explıcita de un objeto. Por ejemplo, muchos programas muestrancuadros de dialogo, y en vez de requerir que se cree codigo que haga la ta-rea, los disenadores de la clase JOptionPane declararon un metodo estaticoque realiza la tarea del programador. Un metodo estatico generalmente esllamado usando el nombre de la clase seguido por un punto y el nombre delmetodo.

2.2. Ingresando texto en un cuadro de dialo-

go

La aplicacion que se muestra enseguida usa otro cuadro de dialogo pre-definido JOptionPane llamado dialogo de entrada, que permite al usuarioingresar datos en el programa. El programa pide el nombre del usuario, yresponde con un cuadro de mensaje conteniendo un saludo y el nombre queel usuario haya ingresado.

1 // NombreDialogo.java

2 // Entrada Basica con un cuadro de dialogo.

3

4 import javax.swing.JOptionPane;

5 public class NombreDialogo {

Page 11: notasGUI

2.2 Ingresando texto en un cuadro de dialogo 11

6

7 public static void main( String args[] ) {

8 // solicitar al usuario que ingrese un nombre

9 String nombre =

10 JOptionPane.showInputDialog( "¿Cual es tu nombre?" );

11 // crear el mensaje

12 String mensaje = String.format(

13 "¡Bienvenido, %s, a la Programacion con Java!", nombre );

14 // mostrar el mensaje de bienvenida al usuario

15 JOptionPane.showMessageDialog( null, mensaje );

16 } // fin de main

17 } // fin de la clase NombreDialogo

Las lıneas 9–10 usan el metodo showInputDialog de JOptionPane paramostrar un dialogo de entrada conteniendo un mensaje y un campo, conocidocomo campo de texto, en el cual el usuario puede poner texto. El argumentopasado al metodo es el mensaje que indica lo que el usuario debera ingresar.El usuario teclea caracteres en el campo de texto, y despues pulsa el botonAceptar o tambien puede presionar la tecla Intro para mandar la cadena alprograma. El metodo showInputDialog devuelve un String conteniendo loscaracteres tecleados por el usuario. La cadena es almacenada en la variablenombre. Si se presiona el boton Cancelar en el dialogo, el metodo regresanull y el programa muestra la palabra “null” como el nombre.

Las lıneas 12–13 usan el metodo estatico format que devuelve un String

para regresar una cadena conteniendo el saludo con el nombre del usuario.El metodo format es parecido al metodo System.out.printf, excepto queformat regresa la cadena formateada en vez de mostrarla. La lınea 14 muestrael saludo en un mensaje de dialogo.

2.2.1. Ejercicios

1. Escribir un programa que use entradas y salidas con cuadros de dialogocon los metodos de la clase JOptionPane para multiplicar dos numeros.Como el metodo showInputDialog regrese un String, se debera con-vertir el String ingresado por el usuario a un tipo int para hacer elcalculo. El metodo

Integer.parseInt( String s )

toma un argumento tipo String representando un entero y regresa elvalor como un tipo int. El metodo parseInt es un metodo estatico de

Page 12: notasGUI

12 Caso de estudio

la clase Integer del paquete java.lang.

2.3. Creando dibujos simples

Una de las caracterısticas de Java es el soporte de graficos que permitea los programadores visualmente resaltar sus aplicaciones. En esta seccionse muestra una de las capacidades graficas de Java —dibujado de lıneas.Tambien se cubre lo basico para la creacion de una ventana para mostrar undibujo sobre la pantalla de la computadora.

Para dibujar en Java, se requiere entender el sistema de coordenadas, unesquema para identificar cada punto en la pantalla. Por defecto, la esquinasuperior izquierda de un componente GUI tiene coordenadas (0,0). Una parcoordenado esta compuesto de un coordenada en x, en este caso la coordenadahorizontal, y una coordena en y, la coordenada vertical. La coordenada en xes la localidad horizontal moviendose de izquierda a derecha. La coordenadaen y es la localidad vertical moviendose de arriba hacia abajo.

Las coordenadas indican donde el grafico debera ser mostrado en pantalla.Las unidades de las coordenadas estan medidas en pıxeles. Un pixel es launidad mas pequena de resolucion que despliega el monitor. El termino pixelviene de las palabras del ingles picture element.

La aplicacion que se muestra a continuacion solo dibuja dos lıneas. La cla-se DibujaPanel realiza el dibujo actual, mientras la clase DibujaPanelPruebacrea una ventana para mostrar el dibujo. En la clase DibujaPanel, las sen-tencias import en las lıneas 4–5 permiten usar la clase Graphics del paquetejava.awt, el cual proporciona varios metodos para dibujar texto y figurassobre la pantalla, y la clase JPanel del paquete javax.swing proporcionauna area sobre la cual se puede dibujar.

1 // Clase DibujaPanel.java

2 // Usando drawLine para conectar las esquinas de un panel.

3

4 import java.awt.Graphics;

5 import javax.swing.JPanel;

6

7 public class DibujaPanel extends JPanel {

8

9 // dibujar una X desde las esquinas del panel

10 public void paintComponent( Graphics g ) {

11

Page 13: notasGUI

2.3 Creando dibujos simples 13

12 // llamar a paintComponent para asegurar que el panel

13 // se muestra correctamente

14 super.paintComponent( g );

15 int ancho = getWidth(); // ancho total

16 int alto = getHeight(); // altura total

17

18 // dibujar una lınea desde la izquierda superior

19 // hasta la derecha inferior

20 g.drawLine( 0, 0, ancho, alto );

21

22 // dibujar una lınea desde la izquierda inferior

23 // hasta la derecha superior

24 g.drawLine( 0, alto, ancho, 0 );

25 } // fin del metodo paintComponent

26 } // fin de la clase DibujaPanel

En la lınea 7 se usa la palabra reservada extends para indicar que laclase DibujaPanel es una mejora del tipo JPanel. Con extends se indicauna relacion de herencia en la cual la clase DibujaPanel inicia con los miem-bros existentes (datos y metodos) de la clase JPanel. La clase desde la cualDibujaPanel hereda, JPanel, aparece a la derecha de la palabra extends.En esta relacion de herencia, JPanel es llamada la superclase y DibujaPanel

es llamada la subclase. Con lo anterior se obtiene que la clase DibujaPanel

tenga los atributos (datos) y comportamiento (metodos) de la clase JPanel

y ademas las nuevas caracterısticas que se agregan en la declaracion de laclase DibujaPanel —especıficamente, la habilidad para dibujar dos lıneas alo largo de las diagonales del panel.

Cada JPanel, incluyendo DibujaPanel, tienen un metodo paintComponent,lıneas 10–25, el cual es llamado por el sistema automaticamente cada vezque se necesita mostrar el JPanel. Este metodo debera ser sobreescrito si sedesea dibujar algo en el panel. Este metodo es llamado cuando un JPanel esmostrado por primera vez en la pantalla, cuando este es cubierto y despuesdescubierto por alguna ventana, y cuando la ventana es redimensionada. Estemetodo requiere un argumento, un objeto Graphics, que es proporcionadopor el sistema cuando se llama a paintComponent.

La primera sentencia en cada metodo paintComponent que sobreescribaal metodo heredado debera ser

super.paintComponent( g );

lo cual asegura que el panel es dibujado apropiadamente en la pantalla antesde iniciar el dibujo. En las lıneas 15 y 16 se llaman dos metodos que la

Page 14: notasGUI

14 Caso de estudio

clase DibujaPanel hereda de la clase JPanel, en general, cualquier claseque extienda a otra, podra usar cualquier metodo que este declarado enla superclase que tenga al modificador public. Los metodos getWidth ygetHeight regresan el ancho y el alto del JPanel respectivamente, los cualesson almacenados en las variables que estan declaradas en las lıneas 15 y 16.En las lıneas 20 y 24 se usa la referencia g del tipo Graphics para llamar almetodo drawLine que dibujara las lıneas. Los primeros dos argumentos, delmetodo drawLine, son las coordenadas de un extremo de la lınea, y los otrosdos son las coordenadas del otro extremo. Si se redimensiona la ventana laslıneas seran escaladas automaticamente, ya que los argumentos estan basadosen el ancho y alto del panel. Redimensionando la ventana en esta aplicacionprovoca que el sistema llame al metodo paintComponent para redibujar elcontenido de DibujaPanel.

Para mostrar DibujaPanel en la pantalla, se debera colocar este dentro deuna ventana. Se puede crear una ventana con un objeto de la clase JFrame. EnDibujaPanelPrueba, que se muestra enseguida, la lınea 4 se importa la claseJFrame del paquete javax.swing. En la lınea 11 en el metodo main de la cla-se DibujaPanelPrueba se crea una instancia de la clase DibujaPanel, la cualcontendra el dibujo, y la lınea 14 crea un nuevo JFrame que puede contener ymostrar el panel. La lınea 17 llama al metodo setDefaultCloseOperation

con el argumento JFrame.EXIT ON CLOSE para indicar que la aplicacion de-bera terminar cuando el usuario cierre la ventana. La lınea 17 usa el metodoadd de la clase JFrame para poner el panel conteniendo el dibujo en el frame.La lınea 19 pone el tamano del frame, empleando el metodo size dandoledos parametros —el ancho del frame, y el alto. En la lınea 20 se muestra elJFrame.

1 // DibujaPanelPrueba.java

2 // Aplicacion para montar un DibujaPanel.

3

4 import javax.swing.JFrame;

5

6 public class DibujaPanelPrueba {

7

8 public static void main( String args[] ) {

9

10 // crear un panel que contenga el dibujo

11 DibujaPanel panel = new DibujaPanel();

12

13 // crear un nuevo frame para contener al panel

Page 15: notasGUI

2.3 Creando dibujos simples 15

14 JFrame aplicacion = new JFrame();

15

16 // indicar que al salir del frame se cierre la aplicacion

17 aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

18 aplicacion.add( panel ); // agregar el panel al frame

19 aplicacion.setSize( 250, 250 ); // fijar el tama~no del frame

20 aplicacion.setVisible( true ); // hacer visible el frame

21 } // fin de main

22 } // fin de la clase DibujaPanelPrueba

2.3.1. Ejercicios

1. Usando ciclos y sentencias de control dibujar lıneas para obtener disenosinteresantes.

a) Crear un diseno que dibuje lıneas desde la esquina superior izquier-da, desplegandose en abanico hasta que cubran la mitad superiorizquierda del panel. Una aproximacion es dividir el ancho y altoen un numero igual de pedazos (15 pedazos estarıa bien). El pri-mer extremo de una lınea siempre estara en la esquina superiorizquierda (0,0), El segundo extremo puede encontrarse iniciandoen la esquina inferior izquierda, luego moverse hacia arriba un pe-dazo vertical y un pedazo horizontal a la derecha. Dibujar unalınea entre los dos extremos. Continuarse moviendo el extremo,arriba y a la derecha, hasta llegar a la esquina superior derecha.La figura se debera ajustar cuando se redimensione la ventana.

b) Modificiar el programa del ejercicio anterior para desplegar lıneasdesde las cuatro esquinas. Las lıneas de las esquinas opuestas sedeberan intersectar.

2. Realizar los siguientes programas.

a) Crear un diseno iniciando con la division de cada lado del panelen la misma cantidad de partes, se puede escoger 15. La primeralınea inicia en la esquina superior izquierda y termina una partea la derecha sobre el lado inferior. Para las siguientes lıneas, sedebera mover hacia abajo en una parte del lado izquierdo, y unaparte hacia la derecha en el lado inferior. Repetir lo anterior hastaque se alcance en el lado inferior la esquina inferior derecha.

Page 16: notasGUI

16 Caso de estudio

b) Modificar el programa del ejercicio anterior para espejear el disenoen las cuatro esquinas.

2.4. Dibujando rectangulos y elipses

En esta seccion se muestra como dibujar rectangulos y elipses, usando dela clase Graphics los metodos drawRect y drawOval respectivamente.

1 // Figuras.java

2 // Se muestran diferentes figuras que pueden ser dibujadas

3 import java.awt.Graphics;

4 import javax.swing.JPanel;

5

6 public class Figuras extends JPanel {

7 private int opcion; // opcion del usuario de la figura a dibujar

8

9 // El constructor pone la opcion del usuario

10 public Figuras( int opcionUsuario ) {

11 opcion = opcionUsuario;

12 } // fin del constructor Figuras

13

14 // dibujar una cascada de figuras iniciando desde la esquina

15 // superior izquierda

16 public void paintComponent( Graphics g ) {

17 super.paintComponent( g );

18 for ( int i = 0; i < 10; i++ ) {

19 // selecionar la figura basandose en la opcion del usuario

20 switch ( opcion ) {

21 case 1: // dibujar rectangulos pasando las coordenadas del

22 // rectangulo dado por la esquina x, y, con ancho y alt o

23 g.drawRect( 10 + i * 10, 10 + i * 10,

24 50 + i * 10, 50 + i * 10 );

25 break;

26 case 2: // dibujar elipses

27 g.drawOval( 10 + i * 10, 10 + i * 10,

28 50 + i * 10, 50 + i * 10 );

29 break;

30 } // fin del switch

31 } // fin del for

32 } // fin del metodo paintComponent

33 } // fin de la clase Figuras

La lınea 6 inicia con la declaracion de la clase Figuras, la cual extiendea la clase JPanel. La variable de instancia, opcion, declarada en la lınea 7,

Page 17: notasGUI

2.4 Dibujando rectangulos y elipses 17

determina si el metodo paintComponent debera dibujar rectangulos o elipses.El constructor en las lıneas 10–12 inicializa opcion con el valor pasado en elparametro opcionUsuario.

El metodo paintComponent, de las lıneas 16–32, hace el dibujo. No sedebe olvidar que la primera sentencia que debera ser llamada en este metodoes super.paintComponent, como aparece en la lınea 19. Entre las lıneas 18–31 se tiene un ciclo que dibuja 10 figuras. La sentencia switch, lıneas 20–30,selecciona entre dibujar rectangulos y elipses.

Si opcion tiene 1, entonces el programa dibuja un rectangulo, mediantela llamada al metodo drawRect de la clase Graphics en las lıneas 23–24.Este metodo requiere cuatro argumentos, siendo los dos primeros las coor-denadas de la esquina superior izquierda del rectangulo, y los siguientes dosparametros representan el ancho y el alto del rectangulo. En este ejemplo seinicia en una posicion 10 pıxeles abajo y 10 pıxeles a la derecha de la esquinasuperior izquierda, y en cada iteracion del ciclo se mueve la esquina superiorizquierda otros 10 pıxeles hacia abajo y a la derecha. El ancho y la alturadel rectangulo inician en 50 pıxeles y se incrementan en 10 pıxeles en cadaiteracion.

Si opcion tiene 2, el programa dibuja una elipse. Cuando se dibuja unaelipse, se encuentra contenida en un rectangulo, bounding rectangle, y la elipsetoca los cuatro puntos medios del rectangulo. El metodo drawOval, lıneas27–28, requiere los mismos cuatro argumentos que el metodo drawRect. Losargumentos especifican la posicion y el tamano del rectangulo que acota ala elipse. Para este caso son los mismos valores que fueron dados para elrectangulo.

Se muestra enseguida el programa que es el responsable para manejar laentrada del usuario y crear una ventana para desplegar los dibujos apropiadosusando la seleccion del usuario.

1 // ProbarFiguras.java

2 // Aplicacion de prueba que muestra la clase Figuras

3

4 import javax.swing.JFrame;

5 import javax.swing.JOptionPane;

6

7 public class ProbarFiguras {

8

9 public static void main( String args[] ) {

10 // obtener la opcion del usuario

11 String entrada = JOptionPane.showInputDialog(

Page 18: notasGUI

18 Caso de estudio

12 "Ingresar 1 para dibujar rectangulos\n" +

13 "Ingresar 2 para dibujar ovalos" );

14 // convertir la entrada a int

15 int opcion = Integer.parseInt( entrada );

16 // crear el panel con la entrada del usuario

17 Figuras panel = new Figuras( opcion );

18 JFrame application = new JFrame(); // crear a nuevo JFrame

19 application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

20 application.add( panel ); // agregar el panel al frame

21 application.setSize( 300, 300 ); // fijar el tama~no deseado

22 application.setVisible( true ); // mostrar el frame

23 } // fin de main

24 } // fin de la clase ProbarFiguras

En las lıneas 11–13 se pide al usuario, con un cuadro de dialogo de entrada,que seleccione el tipo de figuras a dibujar; la respuesta es almacenada en lavariable entrada. En la lınea 15 se emplea el metodo parseInt de la claseInteger para convertir el String guardado en la variable entrada a un tipoint y se asigna a la variable opcion. Una instancia de la clase Figuras escreada en la lınea 17, pasando la opcion del usuario al constructor. Las lıneas17–22 realizan las operaciones habituales para crear y configurar la ventana—crear un frame, configurar salir cuando la aplicacion sea cerrada, agregarel dibujo al frame, configurar el tamano del frame y hacerlo visible.

2.4.1. Ejercicios

1. Dibujar 12 cırculos concentricos en el centro de un JPanel. El cırculomas interno debera tener un radio de 10 pıxeles, y cada cırculo sucesivodebera tener un radio de 10 pıxeles mas grande que el previo anterior.Iniciar encontrando el centro del JPanel. Para obtener la esquina su-perior izquierda de un cırculo moverse un radio hacia arriba y un radiohacia la izquierda desde el centro. El ancho y el alto del rectanguloacotador es el diametro del cırculo (dos veces el radio).

2. Crear un programa que lea la entrada de varios valores, usando cua-dros de dialogo, para mostrar una grafica de barras con rectangulos, deacuerdo a los valores dados.

Page 19: notasGUI

2.5 Figuras Rellenas y Colores 19

2.5. Figuras Rellenas y Colores

Se pueden crear muchos disenos interesantes con solo lıneas y figuras basi-cas, la clase Graphics proporciona muchas mas capacidades. Se revisaran acontinuacion las caracterısticas de colores y figuras rellenas. Agregando colorse agrega otra caracterıstica a los dibujos que el usuario ve en la computado-ra. Las figuras rellenas cubren totalmente regiones con colores solidos, en vezde solo dibujar los contornos.

Los colores mostrados en las pantallas de las computadoras estan defini-dos por sus partes de rojo, verde y azul. Estas partes, conocidos como valoresRGB (Red Green Blue), tiene valores enteros entre 0 y 255. Entre mas gran-de sea el valor, mayor tinte tendra el color final. Java emplea la clase Color

del paquete java.awt para representar colores usando sus valores RGB. Laclase Color en el paquete java.awt es empleada por Java para representarcolores usando los valores RGB. La clase Color contiene 13 objetos predefini-dos estaticos — Color.BLACK, Color.BLUE, Color.CYAN, Color.DARK GRAY,Color.GRAY, Color.GREEN, Color.LIGHT GRAY, Color.MAGENTA, Color.ORAN-GE, Color.PINK, Color.RED, Color.WHITE y Color.YELLOW. La clase Color

tambien contiene un constructor de la forma:

public Color( int r, int g, int b)

para que se puedan crear colores hechos a la medida especificando los com-ponentes individuales rojo, verde y azul de un color.

Los rectangulos y las elipses rellenas son dibujados con los metodos fillRecty fillOval de la clase Graphics, respectivamente. Estos dos metodos tie-nen los mismos parametros como sus contrapartes sin rillenar drawRect ydrawOval; los primeros dos parametros son las coordenadas para la esquinasuperior izquierda de la figura, mientras los siguientes dos parametros deter-minan su ancho y alto. El codigo de enseguida crea una cara sonriente, verfigura 2.1, empleando colores y figuras rellenas.

1 // CaraSonriente.java

2 // Muestra figuras rellenas

3

4 import java.awt.Color;

5 import java.awt.Graphics;

6 import javax.swing.JPanel;

7

8 class CaraSonriente extends JPanel {

Page 20: notasGUI

20 Caso de estudio

Figura 2.1: Una cara sonriente empleando fillOval y la clasejava.awt.Color

9

10 public void paintComponent( Graphics g ) {

11 super.paintComponent( g );

12 // dibujar la cara

13 g.setColor( Color.YELLOW );

14 g.fillOval( 10, 10, 200, 200 );

15 // draw los ojos

16 g.setColor( Color.BLACK );

17 g.fillOval( 55, 65, 30, 30 );

18 g.fillOval( 135, 65, 30, 30 );

19 // dibujar la boca

20 g.fillOval( 50, 110, 120, 60 );

21 // "retocar" la boca en una sonrisa

22 g.setColor( Color.YELLOW );

23 g.fillRect( 50, 110, 120, 30 );

24 g.fillOval( 50, 120, 120, 40 );

25 } // fin del metodo paintComponent

26 } // fin de CaraSonriente

Las sentencias import en las lıneas 4–6 del codigo anterior importan lasclases Color, Graphics y JPanel. La clase CaraSonriente, lıneas 10–25, usala clase Color para especificar los colores de dibujo, y usa la clase Graphics

para dibujar. La clase JPanel proporciona el area en la cual se dibujara. Enla lınea 13 se emplea setColor de la clase Graphics para indicar el colorcon el que se dibujara usando el color amarillo. El metodo setColor requiereun argumento, el color que sera puesto como el color para dibujar. La lınea14 dibuja un cırculo con diametro 200 para representar la cara. En la lınea16 se pone el color negro, y las lıneas 17 y 18 ponen los ojos. La boca sedibuja con una elipse en la lınea 20, pero no tiene el diseno requerido. Para

Page 21: notasGUI

2.5 Figuras Rellenas y Colores 21

formar la sonrisa en la boca, se retoca la boca. En la lınea 22 se pone el coloramarillo y en la lınea 23 se dibuja un rectangulo que tiene la mitad de alturade la boca, con lo que se borra la mitad superior de la boca, quedando solola mitad inferior visible. Para crear una mejor sonrisa la lınea 24 dibuja otraelipse para cubrir ligeramente la parte superior de la boca.

1 // PruebaCaraSonriente

2 // Probar aplicacion que muestra cara sonriente

3

4 import javax.swing.JFrame;

5

6 public class PruebaCaraSonriente {

7

8 public static void main( String args[] ) {

9 CaraSonriente panel = new CaraSonriente();

10 JFrame aplicacion = new JFrame();

11 aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

12 aplicacion.add( panel );

13 aplicacion.setSize( 230, 250 );

14 aplicacion.setVisible( true );

15 } // fin de main

16 } // fin de la clase PruebaCaraSonriente

La clase PruebaCaraSonriente, codigo de arriba, crea y muestra unJFrame conteniendo el dibujo. Cuando el JFrame es mostrado, el sistemallama al metodo paintComponent para dibujar la cara sonriente.

2.5.1. Ejercicios

1. Usando el metodo fillOval, dibujar una diana que alterne entre doscolores aleatorios. Usar el constructor Color( int r, int g, int b)

con argumentos aleatorios para generar colores aleatorios.

2. Crear un programa que dibuje 10 figuras rellenas aleatorias en colo-res, posiciones y tamanos aleatorios. El metodo paintComponent de-bera contener un ciclo que itere 10 veces. En cada iteracion, el ciclodebera determinar si dibuja un rectangulo relleno o una elipse, crearun color aleatorio y escoger coordenadas y dimensiones aleatorias. Lascoordenadas deberan escogerse basadas en el ancho y alto del panel.Longitudes de los lados deberan limitarse a la mitad del ancho y altode la ventana.

Page 22: notasGUI

22 Caso de estudio

2.6. Dibujo de Arcos

Usando las caracterısticas graficas de Java, se pueden crear dibujos mascomplejos que serıan mas tediosos codificar lınea por lınea. En el siguientecodigo se emplean arreglos y sentencias de repeticion para dibujar un arco iris,ver figura 2.2, usando el metodo fillArc de la clase Graphics. El dibujado dearcos es similar al dibujado de elipses —un arco es simplemente una seccionde una elipse.

Figura 2.2: Dibujo de un arco iris empleando drawArc

1 // DibujaArcorIris.java

2 // Se muestra el uso de colores en un arreglo.

3 import java.awt.Color;

4 import java.awt.Graphics;

5 import javax.swing.JPanel;

6

7 class DibujaArcoIris extends JPanel {

8

9 // Definir el color ındigo y violeta

10 final Color VIOLETA = new Color( 128, 0, 128 );

11 final Color INDIGO = new Color( 75, 0, 130 );

12

13 // Colores para el arco iris, iniciando con el mas interno.

14 // Las dos entradas en blanco dan un arco vacıo en el centro

15 private Color colores[] = {

16 Color.WHITE, Color.WHITE, VIOLETA, INDIGO, Color.BLUE,

17 Color.GREEN, Color.YELLOW, Color.ORANGE, Color.RED

18 };

19

20 // constructor

21 public DibujaArcoIris() {

Page 23: notasGUI

2.6 Dibujo de Arcos 23

22 setBackground( Color.WHITE ); // fijar el fondo a blanco

23 } // fin del constructor DibujaArcoIris

24

25 // dibujar un arco iris usando cırculos concentricos

26 public void paintComponent( Graphics g ) {

27 super.paintComponent( g );

28

29 int radio = 20; // radio de un arco

30

31 // dibujar el arco iris en la parte inferior y al centro

32 int centroX = getWidth() / 2;

33 int centroY = getHeight() - 10;

34

35 // dibujar arcos rellenos iniciando con el mas exterior

36 for ( int i = colores.length; i > 0; i-- ) {

37 // fijar el color para el arco actual

38 g.setColor( colores[ i - 1 ] );

39

40 // fijar el arco desde 0 a 180 grados

41 g.fillArc( centroX - i * radio, centroY - i * radio,

42 i * radio * 2, i * radio * 2, 0, 180 );

43 } // fin del for

44 } // fin del metodo paintComponent

45 } // fin de la clase DibujaArcoIris

El codigo anterior inicia con las sentencias import usuales para crear losdıbujos, lıneas 3–5. Las lıneas 10–11 declaran y crean dos nuevos colores–VIOLETA e INDIGO. Para los colores del arco iris en la clase Color se en-cuentran definidos los primeros 5 de los 7 colores del arco iris. En las lıneas15–17 se inicializa un arreglo con los colores del arco iris, iniciando primerocon los arcos mas internos. El arreglo inicia con dos elementos Color.WHITE,los cuales son para dibujar los arcos vacıos en el centro del arco iris. El cons-tructor de las lıneas 21–23 contiene una sola sentencia que llama al metodosetBackground, el cual se hereda desde la clase JPanel, con el parametroColor.White. El metodo setBackground toma un solo argumento tipo Color

y fija el fondo del componente a ese color.En la lınea 29 se declara la variable local radio, la cual determina el

radio de cada arco. Las variables locales centroX y centroY, lıneas 32–33,determinan la localidad del punto medio en la base de la ventana. El ciclo enlas lıneas 36–43 usa la variable de control i para contar hacia atras a partirdel final del arreglo, dibujando los arcos mas grandes primero y colocandoarcos mas pequenos sucesivante al frente del previo. En la lınea 38 se fija el

Page 24: notasGUI

24 Caso de estudio

color para dibujar el arco actual desde el arreglo.El metodo fillArc usado en las lıneas 41–42 dibuja un semicırculo lleno.

Este metodo requiere seis parametros. Los primeros cuatro representan elrectangulo acotador en el cual el arco sera dibujado. Los primeros dos deestos indican las coordenadas de la esquina superior izquierda del rectanguloacotador, y los siguientes dos indican el ancho y alto. El quinto parametroes el angulo inicial en la elipse, y el sexto indica el barrido, o la cantidad dearco a cubrir. El angulo inicial y de barrido estan medidos en grados, concero grados apuntando a la derecha. Un barrido positivo dibuja el arco ensentido contrario a las manecillas, mientras uno negativo dibuja en el sentidode las manecillas. Un metodo similar a fillArc es drawArc —este requierelos mismos parametros como fillArc, pero dibuja la arista del arco en vezde llenarlo.

1 // PruebaDibujaArcoIris.java

2 // Aplicacion de prueba para mostrar un arco iris.

3

4 import javax.swing.JFrame;

5

6 public class PruebaDibujaArcoIris {

7

8 public static void main( String args[] ) {

9 DibujaArcoIris panel = new DibujaArcoIris();

10 JFrame aplicacion = new JFrame();

11 aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

12 aplicacion.add( panel );

13 aplicacion.setSize( 400, 250 );

14 aplicacion.setVisible( true );

15 } // fin del main

16 } // fin de la clase PruebaDibujaArcoIris

La clase PruebaDibujaArcoIris, codigo anterior, crea y configura unJFrame para mostrar el arco iris. Una vez que el programa hace al panel visi-ble, el sistema llama al metodo paintComponent de la clase DibujaArcoIrispara dibujar el arco iris en la pantalla.

2.6.1. Ejercicios

1. En el ejercicio, se dibujaran espirales, ver figura 2.3, con los metodosdrawLine y drawArc. Las espirales deberan cubrir todo el panel, nodebe haber zonas sin llenar al redimensionar la ventana.

Page 25: notasGUI

2.7 Usando objetos con graficas 25

a) Dibujar una espiral cuadrada centrada en el panel, usando el meto-do drawLine. Una tecnica es usar un ciclo que incremente la lon-gitud de la lınea despues de dibujar la segunda lınea. La direccionpara dibujar la siguiente linea debera seguir un patron, como aba-jo, izquierda, arriba, derecha.

b) Dibujar una espiral circular usando el metodo drawArc para dibu-jar un semicırculo cada vez. Cada semicırculo sucesivo debera te-ner un radio mayor y debera continuar dibujando donde el se-micırculo previo termino.

Figura 2.3: Dibujo de espirales usando drawLine y drawArc

2.7. Usando objetos con graficas

Los ejemplos que se han revisado hasta ahora no varıan cada vez que seejecuta el programa. Sin embargo, en el segundo ejercicio de la subseccion2.5.1 se pide crear un programa que genera figuras y colores de manera alea-toria. En aquel ejercicio, el dibujo cambia cada vez que el sistema llama apaintComponent para redibujar la pantalla. Para crear un dibujo mas con-sistente que permanezca igual cada vez que es dibujado, se debe guardar lainformacion acerca de las figuras mostradas para que se puedan reproducirde forma exacta cada vez que el sistema llame a paintComponent.

Page 26: notasGUI

26 Caso de estudio

Para realizar lo anterior, se creara un conjunto de clases de figuras queguardaran informacion acerca de cada figura. Se haran estas clases “inteli-gentes” permitiendo que objetos de estas clases dibujarse a si mismo si seproporciona un objeto Graphics. En el codigo que aparace enseguida, la claseMiLinea tiene todas las capacidades indicadas.

La clase MiLinea importa las clases Color y Graphics en las lıneas 3–4.Las lıneas 8–12 declaran variables de instancia para las coordenadas nece-sarias para dibujar una lınea, y la lınea 12 declara la variable de instanciaque guarda el color de la lınea. El constructor en las lıneas 15–21 toma cincoparametros, uno para cada variable de instancia que se inicializara. El meto-do dibujar en las lıneas 24–27 necesita un objeto Graphics que es usadopara dibujar la lınea en el color y las coordenadas apropiadas.

1 // MiLinea.java

2 // Declaracion de la clase MiLinea

3 import java.awt.Color;

4 import java.awt.Graphics;

5

6 public class MiLinea {

7

8 private int x1; // coordenada en x del primer extremo

9 private int y1; // coordenada en y del primer extremo

10 private int x2; // coordenada en x del segundo extremo

11 private int y2; // coordenada en y del segundo extremo

12 private Color miColor; // color de esta figura

13

14 // constructor con valores de entradas

15 public MiLinea( int x1, int y1, int x2, int y2, Color color ) {

16 this.x1 = x1; // poner el valor en x del primer extremo

17 this.y1 = y1; // poner el valor en y del primer extremo

18 this.x2 = x2; // poner el valor en x del segundo extremo

19 this.y2 = y2; // poner el valor en y del segundo extremo

20 miColor = color; // poner el color

21 } // fin del constructor MiLinea

22

23 // Dibujar la lınea en el color indicado

24 public void dibujar( Graphics g ) {

25 g.setColor( miColor );

26 g.drawLine( x1, y1, x2, y2 );

27 } // fin del metodo dibujar

28 } // fin de la clase MiLinea

A continuacion se declara la clase DibujaPanel.java, la cual generara ob-jetos aleatorios de la clase MiLinea. La lınea 11 declara un arreglo MiLinea

Page 27: notasGUI

2.7 Usando objetos con graficas 27

para guardar las lıneas a dibujar. Dentro del constructor, lıneas 14–35, en lalınea 15 se fija el color del fondo a Color.WHITE. La lınea 17 crea el arreglocon una longitud aleatoria entre 5 y 9. El ciclo, en las lıneas 20–34 crea unnuevo MiLinea para cada elemento en el arreglo. Las lıneas 22–25 generancoordenadas aleatorias para cada los extremos de cada lınea, en las lıneas28–30 se genera un color aleatorio para la lınea. En la lınea 33 se crea unnuevo objeto MiLinea con los valores generados aleatoriamente y se guardaeste en el arreglo.

El metodo paintComponent itera con los objetos MiLinea en el arre-glo lineas usando una version mejorada del ciclo for, lıneas 41–42. Cadaiteracion llama el metodo dibujar del objeto actual MiLinea y le pasa el ob-jeto Graphics para dibujarlo en el panel. La clase PruebaDibujo, siguientecodigo, configura una nueva ventana para mostrar el dibujo. Como se estanfijando las coordenadas para las lıneas solamente una vez en el constructor,el dibujo no cambia si paintComponent es llamado para refrescar el dibujadoen la pantalla.

1 // DibujaPanel.java

2 // Programa que usa la clase MiLinea

3 // para dibujar lıneas aleatorias

4 import java.awt.Color;

5 import java.awt.Graphics;

6 import java.util.Random;

7 import javax.swing.JPanel;

8

9 public class DibujaPanel extends JPanel {

10 private Random numerosAleatorios = new Random();

11 private MiLinea lineas[]; // arreglo de lıneas

12

13 // constructor, crea un panel con figuras aleatorias

14 public DibujaPanel() {

15 setBackground( Color.WHITE );

16

17 lineas = new MiLinea[ 5 + numerosAleatorios.nextInt( 5 ) ];

18

19 // crear lıneas

20 for ( int i = 0; i < lineas.length; i++ ) {

21 // generar numeros aleatorios

22 int x1 = numerosAleatorios.nextInt( 300 );

23 int y1 = numerosAleatorios.nextInt( 300 );

24 int x2 = numerosAleatorios.nextInt( 300 );

25 int y2 = numerosAleatorios.nextInt( 300 );

Page 28: notasGUI

28 Caso de estudio

26

27 // generar un color aleatorio

28 Color color = new Color( numerosAleatorios.nextInt( 256 ),

29 numerosAleatorios.nextInt( 256 ),

30 numerosAleatorios.nextInt( 256 ) );

31

32 // agregrar la lınea a la lista de lıneas que seran mostradas.

33 lineas[ i ] = new MiLinea( x1, y1, x2, y2, color );

34 } // fin del for

35 } // fin del constructor DrawPanel

36

37 // para cada figura del arreglo, dibujar las figuras individuales

38 public void paintComponent( Graphics g ) {

39 super.paintComponent( g );

40 // dibujar las lıneas

41 for ( MiLinea linea : lineas )

42 linea.dibujar( g );

43 } // fin del metodo paintComponent

44 } // fin de la clase DibujaPanel

1 // PruebaDibuja.java

2 // Aplicacion de prueba para mostrar un DibujaPanel.

3

4 import javax.swing.JFrame;

5

6 public class PruebaDibujo {

7

8 public static void main( String args[] ) {

9

10 DibujaPanel panel = new DibujaPanel();

11 JFrame application = new JFrame();

12

13 application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

14 application.add( panel );

15 application.setSize( 300, 300 );

16 application.setVisible( true );

17 } // fin de main

18 } // fin de la clase PruebaDibujo

2.7.1. Ejercicios

1. Extender el programa de esta seccion para dibujar aleatoriamente rectangu-los y elipses. Crear las clases MiRectangulo y MiElipse. Ambas clasesdeberan incluir coordenadas x1, y1, x2, y2, un color y un valor boo-

Page 29: notasGUI

2.7 Usando objetos con graficas 29

leano para determinar si la figura es rellena. Declarar un constructoren cada clase con argumentos para inicializar todas las variables deinstancia. Para ayudar a dibujar rectangulos y elipses, cada clase de-bera dar metodos getSuperiorIzquierdaX, getSuperiorIzquierdaY,getAncho y getAlto que calculen la coordenada superior izquierda x,la coordenada superior izquierda y, el ancho y el alto, respectivamen-te. La coordenada superior izquierda x, es el valor mas pequeno de lasdos coordenadas x, de manera similar para la coordenada superior y,el ancho es el valor absoluto de la diferencia entre las abscisas, y laaltura es el valor absoluto de la diferencia entre las dos ordenadas delos extremos.

La clase DibujaPanel, la cual extiende a JPanel, maneja la creacionde las figuras, debera declarar tres arreglos, uno para cada forma defigura. La longitud de cada arreglo debera ser un numero aleatorio entre1 y 5. El constructor de la clase DibujaPanel llenara cada uno de losarreglos con figuras de posicion, tamano, color y llenado aleatorio, comose indica en el ejercicio 2 de la seccion 2.5.1.

Adicionalmente, modificar las tres clases de figuras para incluir lo si-guiente:

a) Un constructor sin argumentos que fija todas las coordenadas dela figura a cero, el color de la figura a color negro, y la propiedad dellenado a false, esto ultimo solo para MiRectangulo y MiElipse.

b) Metodos set para las variables de instancia en cada clase. Losmetodos que fijen un valor coordenado deberan verificar que elargumento es mayor que, o igual a cero antes de fijar la coordenada— si no, estos deberan poner la coordenada a cero. El constructordebera llamar a los metodos set en vez de inicializar las variablesde instancia directamente.

c) Metodos get para las variables de instancia en cada clase. El meto-do dibujar debera referenciar las coordenadas por los metodos geten vez de acceder directamente a las variables.

Page 30: notasGUI

30 Caso de estudio

2.8. Texto e imagenes con etiquetas

Los programas frecuentemente usan etiquetas cuando requieren mostrarinformacion o instrucciones al usuario en una interfaz grafica. Las etiquetasson una forma conveniente para identificar componentes GUI en la pantallay para mantener informado al usuario respecto al estado actual del progra-ma. En Java, un objeto de la clase JLabel del paquete javax.swing puedemostrar una sola lınea de texto, una imagen o ambos. El siguiente ejemplomuestra varias caracterısticas de JLabel.

1 // LabelDemo.java

2 // Muestra el uso de etiquetas

3 import java.awt.BorderLayout;

4 import javax.swing.ImageIcon;

5 import javax.swing.JLabel;

6 import javax.swing.JFrame;

7

8 public class LabelDemo {

9

10 public static void main( String args[] ) {

11 // crear una etiqueta plana con texto

12 JLabel etiquetaNorte = new JLabel( "Norte" );

13

14 // crear un icono desde una imagen para ponerlo en un JLabel

15 ImageIcon iconoEtiqueta = new ImageIcon( "gnome-gnibbles.png" );

16

17 // crear una etiqueta con un icono en vez de texto

18 JLabel etiquetaCentro = new JLabel( iconoEtiqueta );

19

20 // crear otra etiqueta con un icono

21 JLabel etiquetaSur = new JLabel( iconoEtiqueta );

22

23 // configurar etiqueta para mostrar texto, al igual que el icono

24 etiquetaSur.setText( "Sur" );

25

26 // crear una ventana para poner las etiquetas

27 JFrame aplicacion = new JFrame();

28

29 aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

30

31 // agregar las etiquetas a la ventana, el segundo argumento indica

32 // en que lugar de la ventana se pondra la etiqueta

33 aplicacion.add( etiquetaNorte, BorderLayout.NORTH );

34 aplicacion.add( etiquetaCentro, BorderLayout.CENTER );

Page 31: notasGUI

2.8 Texto e imagenes con etiquetas 31

35 aplicacion.add( etiquetaSur, BorderLayout.SOUTH );

36

37 aplicacion.setSize( 300, 300 ); // fijar el tama~no de la ventana

38 aplicacion.setVisible( true ); // mostrar la ventana

39 } // fin de main

40 } // fin de la clase LabelDemo

En las lıneas 3–6 se importan las clases que se requieren para mostrar lasetiquetas. BorderLayout del paquete java.awt tiene constantes para indicardonde se pueden colocar componentes GUI en un JFrame. La clase ImageIconrepresenta una imagen que puede ser mostrada en un JLabel, y la claseJFrame representa la ventana que contendra todas las etiquetas.

La lınea 12 crea un JLabel que muestra su argumento para el constructor—la cadena "Norte". La lınea 15 declara la variable local iconoEtiquetay le asigna un nuevo ImageIcon. El constructor para ImageIcon recibe unacadena que indica el camino a la imagen. Como solamente se indica un nom-bre de archivo, Java supone se encuentra en el mismo directorio de la cla-se LabelDemo. ImageIcon puede cargar imagenes en formato GIF, JPEG yPNG. La lıena 18 declara e inicializa la variable local etiquetaCentro conun JLabel que muestra a iconoEtiqueta. Sin embargo, en la lınea 24 sellama al metodo setText para cambiar el texto que la etiqueta muestra. Elmetodo setText puede ser llamado por cualquier JLabel para cambiar sutexto. Este JLabel mostrara el icono y el texto.

En la lınea 27 se crea un JFrame que mostrara los JLabels, y la lınea29 indica que el programa debera terminar cuando el JFrame se cierre. Seponene las etiquetas en la ventana en las lıneas 33–35 llamando una versionsobrecargada del metodo add que toma dos parametros. El primer metodo esel componente que se quiere poner, y el segundo es la region en la cual estedebera ser puesto. Cada JFrame tiene asociado un manejador que ayuda enla posicion de los componentes que tiene puestos. El manejado por defectopara un JFrame es el conocido como BorderLayout y tiene cinco regiones —NORTH (superior), SOUTH (inferior), EAST (lado derecho), WEST (lado izquierdo)y CENTER (centro). Cada uno de estos esta declarado como una constante enla clase BorderLayout. Cuando se llama al metodo add con un argumento,el JFrame coloca al componente usando CENTER automaticamente. Si unaposicion ya contenıa un componente, entonces el nuevo componente toma sulugar. En las lıneas 27 y 39 se pone el tamano de la ventana y se hace visibleen pantalla.

Page 32: notasGUI

32 Caso de estudio

2.8.1. Ejercicio

1. Modificar el ejercicio 1 de la seccion 2.7.1 para incluir un JLabel comouna barra de estado que muestre la cantidad de cada figura dibujada,podrıa tener un texto como: ”Lıneas 3, Elipses 2, Rectangulos 4 ”. Laclase DibujaPanel debera declarar un metodo que regrese una cadenaconteniendo el texto del estado. En el metodo main, primero crear elDibujaPanel, despues crear el JLabel con el texto del estado comoun argumento del constructor JLabel. Poner el JLabel en la regioninferior de la ventana.

2.9. Dibujado con polimorfismo

Como se puede observar en el ejercicio 1 de la seccion 2.7.1, y en lamodificacion solicitada en el ejercicio 1 de la seccion 2.8.1 existen muchassimilaridades entre las clases de las figuras. Usando herencia se pueden “fac-torizar” las caracterısticas comunes de las tres clases y colocarlas en una solasuperclase. Se pueden entonces manipular los todos los objetos, de tres tiposde figuras, polimorficamente usando variables del tipo de la superclase. Re-moviendo la redundancia en el codigo resultara un programa mas pequeno yflexible que es mas facil de mantener.

2.9.1. Ejercicios

1. Modificar las clases MiLinea, MiElipse y MiRectangulo del ejerciciouno de la seccion 2.7.1 y 2.8.1 para crear la siguiente jerarquıa de clases:

La clase MiFigura es una subclase de java.lang.Object

Las clases MiLinea, MiElipse y MiRectangulo son subclases deMiFigura.

Las subclases de la jerarquıa MiFigura deberan ser clases figura “inte-ligentes” para saber como dibujarse ellas si se proporciona un objetoGraphics que les diga donde dibujar. Una vez que el programa cree unobjeto de la jerarquıa, este lo puede manipular polimorficamente porel resto de su existencia como un MiFigura.

En la solucion, la clase MiFigura debera ser abstract. Como MiFigura

representa cualquier figura en general, no se puede implementar el

Page 33: notasGUI

2.9 Dibujado con polimorfismo 33

metodo dibujar sin saber exactamente que figura es. Los datos re-presentando las coordenadas y el color de las figuras en la jerarquıadeberan ser declarados como miembros private de la clase MiFigura.Ademas de los datos comunes, la clase MiFigura debera declarar lossiguientes metodos:

a) Un constructor sin argumentos que ponga todas las coordenadasde la figura en cero y el color en negro.

b) Un constructor que inicialize las coordenadas y el color con losvalores de los argumentos proporcionados.

c) Metodos set para las coordenadas individuales y el color que per-mitan al programador poner cualquier parte de los datos indepen-dientemente para una figura en la jerarquıa.

d) Metodos get para las coordenadas individuales y el color que per-mitan al programador recuperar cualquier parte de los datos in-dependientemente para una figura en la jerarquıa.

e) El metodo abstract

public abstract void dibujar( Graphics g );

el cual sera llamado por el metodo paintComponent del programapara dibujar una figura en la pantalla.

Para asegurar la encapsulacion, todos los datos en la clase MiFigura

deberan ser private. Esto requiere declarar metodos set y get para ma-nipular los datos. La clase MiLinea debera proporcionar un constructorsin argumentos y un constructor con argumentos para las coordenadasy el color. Las clases MiElipse y MiRectangulo deberan proporcionarun constructor sin argumentos y un constructor con argumentos paralas coordenadas, el color y para saber si la figura es rellena. El cons-tructor sin argumentos debera, adicionalmente de poner los valores pordefecto, fijar la figura sin relleno.

Se pueden dibujar lıneas, rectangulos, y elipses si se conocen dos pun-tos en el plano. Las lıneas requieren las coordenadas x1, y1, x2 y y2.El metodo drawLine de la clase Graphics conectara los dos puntosdados con un lınea. Si se tienen los mismos cuatro valores para elipsesy rectangulos, se pueden calcular los argumentos necesarios para dibu-jarlos. Cada uno requiere el valor x de la esquina superior izquierda

Page 34: notasGUI

34 Caso de estudio

(el mas pequeno de las x de las dos abscisas), y de la esquina superiorizquierda (el mas pequeno de las y de las dos ordenadas), un ancho (elvalor absoluto de la diferencia de las dos abscisas) y un alto (el valorabsoluto de la diferencia de las dos ordenadas). Los rectangulos y laselipses podrıan tambien tener una bandera relleno que determine sise dibuja la figura como rellena.

No debera haber en el programa variables MiLinea, MiRectangulo,o MiElipse —solamente variables MiFigura que contengan referen-cias a objetos tipo MiLinea, MiRectangulo, o MiElipse. El programadebera generar figuras aleatorias y guardarlas en un arreglo del tipoMiFigura. El metodo paintComponent debera recorrer el arreglo tipoMiFigura y dibujar cada figura (es decir, llamando polimorficamenteal metodo dibujar de cada figura.

Permitir al usuario indicar, con un cuadro de dialogo de entrada, elnumero de figuras que se generaran. El programa entonces las generay las muestra con una barra de estado que informa al usuario cuantasfiguras de cada una fueron creadas.

2. En el ejercicio 1, se creo una jerarquıa MiFigura en donde las clasesMiLinea, MiRectangulo y MiElipse extienden directamente a MiFigura.Si la jerarquıa fue disenada adecuadamente, se podra observar las simi-laridades entre las clases MiRectangulo y MiElipse. Redisenar y reim-plementar el codigo para las clases MiRectangulo y MiElipse para fac-torizar las caracterısticas comunes en la clase abstracta MiFiguraAcotadapara generar la siguiente jerarquıa.

La clase MiFigura es una subclase de java.lang.Object

Las clases MiLinea y MiFiguraAcotada son subclases de MiFigura.

Las clases MiElipse y MiRectangulo son subclases de MiFiguraAcotada.

La clase MiFiguraAcotada debera declarar dos constructores que imi-ten a los de la clase MiFigura y que agreguen un parametro para ponersi la figura es rellena. La clase MiFiguraAcotada debera tambien decla-rar metodos set y get para manipular el campo relleno y metodos quecalculen la coordenada x de la esquina superior izquierda, la coordena-da y de la esquina superior izquierda, el ancho y el alto. Si esta biendisenado, las nuevas clases MiElipse y MiRectangulo deberan tenercada una dos constructores y un metodo dibujar.

Page 35: notasGUI

Capıtulo 3

Componentes GUI

3.1. Introduccion

Una interfaz grafica de usuario GUI (graphical user interface) presentaun mecanismo amigable al usuario para interactuar con una aplicacion. UnaGUI da a una aplicacion una apariencia y comportamiento.

Las GUI estan construıdas con componentes GUI. Estos algunas vecesson llamados controles o widgets—abreviatura de window gadget—enotros lenguajes. Un componente GUI es un objeto con el cual el usuariointeractua usando el raton, el teclado u otra forma de entrada, como el reco-nocimiento de voz.

3.2. Generalidades de Componentes Swing

Se revisan varios componentes GUI que permiten a los desarrolladores deaplicaciones crear GUIs robustos. En la siguiente tabla se muestran varioscomponentes GUI tipo Swing del paquete javax.swing que son usadospara construir GUIs de Java.

Page 36: notasGUI

36 Componentes GUI

Componente DescripcionJLabel Muestra texto o iconos no editables.JTextField Permite al usuario ingresar datos desde

el teclado. Puede tambien ser usado paramostrar texto editable o no editable.

JButton Dispara un evento cuando se pulsa conel raton.

JCheckBox Indica una opcion que puede ser o no se-leccionada.

JComboBox Da una lista de artıculos que abren haciaabajo (drop-down) de las cuales el usua-rio puede hacer una seleccion pulsandosobre un artıculo o posiblemente teclean-do en el cuadro.

JList Da una lista de artıculos de los cualesel usuario puede hacer una seleccion pul-sando en cualquier artıculo en la lista.Elementos multiples pueden ser seleccio-nados.

JPanel Da una area en la cual los componen-tes pueden ser colocados y organizados.Puede tambien ser usado como area dedibujo para graficas.

Varios componentes Swing son componentes puros de Java —estan escri-tos, manipulados y desplegados completamente en Java. Estos son parte deJFC (Java Foundation Classes) —bibliotecas de Java para desarrollo GUIde plataforma cruzada.

Swing vs. AWT. Hay actualmente dos conjuntos de componentes GUI enJava. Antes de que Swing fuera introducido en Java SE 1.2, la GUI de Ja-va era construida con componentes de AWT del paquete java.awt. Cuandouna aplicacion Java con un GUI de AWT se ejecuta en diferentes platafor-mas JAVA, los componentes de la aplicacion GUI se muestran diferentes encada plataforma. Por ejemplo, una aplicacion que muestre un objeto del tipoButton del paquete java.awt, en un computadora que ejecute el sistema ope-rativo Windows, el boton tendra la misma apariencia de los botones de otrasaplicaciones para ese sistema, es decir, los componentes se veran, para algun

Page 37: notasGUI

3.2 Generalidades de Componentes Swing 37

sistema operativo grafico, como los componentes de las otras aplicaciones.Por otra parte, la forma en la cual un usuario interactua con un componenteAWT difiere entre plataformas.

Los componentes GUI de Swing permiten especificar un look-and-feel (laapariencia y la forma en la cual el usuario interacciona con la aplicacion)uniforme para la aplicacion para todas las plataformas o usar de cada pla-taforma el look-and-feel de la plataforma. Una aplicacion puede cambiar suapariencia durante la ejecucion para permitir al usuario escoger su aparienciapreferida.

Componentes peso ligero vs peso pesado. Muchos componentes Swingno estan empatados a los componentes GUI soportados por la plataformasubyacente en la cual la aplicacion se ejecuta. Tales componentes GUI sonconocidos como componentes de peso ligero o lightweight. Los componentesAWT, muchos son paralelos a los componentes Swing, estan empatados a laplataforma local y son llamados componentes de peso pesado o heavyweight,porque descansan en la plataforma local del sistema de ventanas para deter-minar su funcionalidad y su apariencia.

Varios componentes Swing son componentes pesados. Parecidos a los com-ponentes AWT, los componentes GUI pesados de Swing requieren interacciondirecta con el sistema de ventanas local, lo cual podrıa restringir su aparienciay funcionalidad, haciendolos menos flexibles que los componentes ligeros.

Superclases de los componentes ligeros La clase Object es la super-clase de la jerarquıa de clases de Java.

La clase Component del paquete java.awt es una subclase de Object

que declara varios atributos y comportamientos comunes a los componentesGUI en los paquetes java.awt y javax.swing. Muchos componentes GUIextienden la clase Component directamente o indirectamente.

La clase Container en el paquete java.awt es una subclase de Component.Los componentes son puestos en Containers, como ventanas, por lo que loscomponentes pueden ser organizados y mostrados en la pantalla. Cualquierobjeto, que es del tipo Container, puede ser usado para organizar otrosComponents en una GUI. Como un Container es un Component, se puedenadjuntar Containers a otro Container para ayudar a organizar la GUI.

La clase JComponent del paquete javax.swing es una subclase Container.JComponent es la superclase de todos los componentes ligeros Swing y de-

Page 38: notasGUI

38 Componentes GUI

clara sus atributos comunes y comportamientos. Como JComponent es unasubclase de Container, todos los componentes ligeros de Swing son tam-bien Container. Algunas caracterısticas comunes de los componentes ligerossoportadas por JComponent incluyen:

1. Un look-and-feel enchufable que puede ser usado para configurar laapariencia de componentes.

2. Accesos rapidos de teclado, llamados nemotecnicos, para el acceso di-recto a los componentes GUI a traves del teclado.

3. Capacidades comunes de manejo de eventos para casos donde varioscomponentes GUI inician las mismas acciones en una aplicacion.

4. Breves descripciones del proposito de los componentes GUI, llamadossugerencias (tool tips), que son mostrados por un perıodo corto cuandoel cursor del raton es posicionado sobre el componente.

5. Soporte para tecnologıas asistentes, tales como lectores braille para losimpedidos visualmente.

6. Soporte para localizacion de interfaz-usuario —esto es, configurar lainterfaz del usuario para mostrar en diferentes lenguas y convencionesculturales locales.

3.3. Mostrar texto e imagenes en una venta-

na

Se presenta en el siguiente ejemplo un framework (marco) para construiraplicaciones GUI. El framework usa varios conceptos que se veran en variasaplicaciones GUI. Este es el primer ejemplo en el cual la aplicacion apareceen su propia ventana. Muchas ventanas que se crearan seran una instancia dela clase JFrame o una subclase de JFrame. JFrame proporciona los atributosbasicos y comportamientos de una ventana —una barra de tıtulo en la partesuperior de la ventana, y botones para minimizar, maximizar, y cerrar laventana. Como una aplicacion GUI es tıpicamente especifica a la aplicacion,varios de los ejemplos consistiran de dos clases —una subclase de JFrame

que ayuda a mostrar nuevos conceptos GUI y una clase aplicacion en la cualmain crea y muestra la ventana primaria de la aplicacion.

Page 39: notasGUI

3.3 Mostrar texto e imagenes en una ventana 39

Una GUI tıpica consiste de varios componentes. En un GUI grande pue-de ser difıcil identificar el proposito de cada componente a menos que eldisenador de la GUI proporcione instrucciones de texto o informacion in-dicando el proposito de cada componente. Tal texto es conocido como unaetiqueta y es creado con la clase JLabel —una subclase de JComponent. UnJLabel muestra una lınea de texto de solo lectura, una imagen, o ambas.Las aplicaciones raramente cambian el contenido de una etiqueta despues dehaberla creado.

La aplicacion VentanaLabel muestra varias capacidades de JLabel ymuestra el marco que sera usado en la mayorıa de los ejemplos GUI. Haymuchas mas caracterısticas de cada componente GUI que las vistas en losejemplos. Para revisar los detalles completos de cada componente GUI, serecomienda revisar la documentacion.

La clase VentanaLabel, que se muestra a continuacion, es una subclasede JFrame. Se usara una instancia de la clase VentanaLabel para mostraruna ventana conteniendo tres JLabels. Las lıneas 4–9 importan las clasesusadas en la clase VentanaLabel. La clase extiende a JFrame para heredarlas caracterısticas de una ventana. Las lıneas 13–15 declaran las variablesde instancias de las tres JLabel, cada una de las cuales es instanciada en elconstructor de VentanaLabel en las lıneas 18–43. Tıpicamente, el constructorde la subclase del JFrame construye la GUI que es mostrada en la ventanacuando la aplicacion se ejecuta. La lınea invoca al constructor de la superclaseJFrame con el argumento "Probando JLabel". El constructor de JFrame

emplea el String como el texto de la barra de tıtulos de la ventana.

1 // VentanaLabel.java

2 // Demostracion de la clase JLabel.

3

4 import java.awt.FlowLayout; // indica como los componentes son arreglados

5 import javax.swing.JFrame; // proporciona capacidades basicas de ventana

6 import javax.swing.JLabel; // muestra texto e imagenes

7 import javax.swing.SwingConstants; // constantes comunes usadas con Swing

8 import javax.swing.Icon; // interfaz usada para manipular imagenes

9 import javax.swing.ImageIcon; // carga imagenes

10

11 public class VentanaLabel extends JFrame {

12

13 private JLabel etiq1; // JLabel con solo texto

14 private JLabel etiq2; // JLabel construıda con texto e icono

15 private JLabel etiq3; // JLabel con texto e icono agregado

16

Page 40: notasGUI

40 Componentes GUI

17 // constructor VentanaLabel agrega JLabels al JFrame

18 public VentanaLabel() {

19 super( "Probando JLabel" );

20 setLayout( new FlowLayout() ); // fijar el manejador de componentes

21

22 // constructor JLabel con un argumento de cadena

23 etiq1 = new JLabel( "Etiqueta con texto" );

24 etiq1.setToolTipText( "Esto es etiq1" );

25 add( etiq1 ); // agregar etiq1 a JFrame

26

27 // constructor JLabel con cadena, icono y argumentos alineados

28 Icon gusano = new ImageIcon(

29 getClass().getResource( "gnome-gnibbles.png" ));

30 etiq2 = new JLabel( "Label con texto e icono", gusano,

31 SwingConstants.LEFT );

32 etiq2.setToolTipText( "Esto es etiq2" );

33 add( etiq2 ); // agregar etiq2 a JFrame

34

35 etiq3 = new JLabel(); // constructor JLabel sin argumentos

36 etiq3.setText( "Label con icono y texto en el fondo" );

37

38 etiq3.setIcon( gusano ); // agregar icono a JLabel

39 etiq3.setHorizontalTextPosition( SwingConstants.CENTER );

40 etiq3.setVerticalTextPosition( SwingConstants.BOTTOM );

41 etiq3.setToolTipText( "Esto es etiq3" );

42 add( etiq3 ); // agregar etiq3 a JFrame

43 } // fin del constructor VentanaLabel

44 } // fin de la clase VentanaLabel

1 // PruebaLabel.java

2 // Probador de VentanaLabel.

3

4 import javax.swing.JFrame;

5 public class PruebaLabel {

6

7 public static void main( String args[] ) {

8

9 VentanaLabel ventanaLabel = new VentanaLabel(); // crear VentanaLabel

10 ventanaLabel.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaLabel.setSize( 275, 180 ); // fijar el tama~no de la ventana

12 ventanaLabel.setVisible( true ); // mostrar la ventana

13 } // fin de main

14 } // fin de la clase PruebaLabel

Page 41: notasGUI

3.3 Mostrar texto e imagenes en una ventana 41

Indicando el diseno Cuando se construye una GUI, cada componenteGUI debera estar adjuntado a un contenedor, tal como una ventana creadacon un JFrame. Tambien, el programador debera decidir donde posicionarcada componente GUI. Esto es conocido como especificar el diseno de loscomponentes GUI. Java proporciona varios manejadores de diseno que pue-den ayudar a colocar los componentes.

Varios ambientes integrados de desarrollo o IDEs (Integrated DevelopmentEnvironment) dan herramientas de diseno GUI, en las cuales se puede indicarel tamano exacto y lugar de un componente de forma visual empleando elraton, entonces el IDE generara el codigo GUI por el usuario. Con los IDEs sepuede simplificar la creacion del GUI, sin embargo cada uno tiene diferentescapacidades.

Para los ejemplos que se revisaran, se usaran los manejadores de disenode Java. Uno de estos manejadores de diseno es FlowLayout, en el cual loscomponentes GUI son colocados en un contenedor de izquierda a derecha enel orden en el cual el programa los agrega al contenedor. Cuando no hay masespacio para meter componentes de izquierda a derecha. los componentesse continuan mostrando de izquierda a derecha en la siguiente lınea. Si elcontenedor es redimensionado, un FlowLayout redimensiona los componentespara acomodarlos al nuevo ancho del contenedor, posiblemente con menos omas renglones de componentes GUI. El metodo setLayout es heredado en laclase VentanaLabel indirectamente desde la clase Container. El argumentoal metodo debera ser un objeto de una clase que implementa la interfazLayoutManager, por ejemplo FlowLayout. En la lınea 20 se crea un nuevoobjeto FlowLayout y se pasa su referencia como argumento a setLayout

Creacion y pegado de etiquetas Una vez que se ha indicado el diseno dela ventana, se puede inciar creando y pegando componentes GUI a la ventana.Las lıneas 23, 30, 31 crean objetos JLabel que pasan diferentes referencias yconstantes a los constructores. En la lınea 35 se usa un constructor JLabel sinargumentos, pero posteriormente se indica el texto y el icono con los metodossetText y setIcon respectivamente, como se muestra en las lıneas 36 y 38.En las lıneas 24, 32 y 41 se usa el metodo setToolTipText (heredado porJLabel desde JComponent para indicar la sugerencia que es mostrada cuandoel usuario pone el cursor del raton sobre el JLabel en el GUI.

En la lınea 29, la expresion getClass().getResource("gnome-gnibbles-.png") llama al metodo getClass (heredado desde la clase Object) pa-

Page 42: notasGUI

42 Componentes GUI

ra recuperar una referencia al objeto Class que representa la declaracionde la clase VentanaLabel. Esa referencia es entonces usada para llamar almetodo getResource de Class, la cual regresa la localidad de la imagencomo un URL (uniform resource locator). El constructor ImageIcon usa elURL para localizar la imagen, y entonces cargarla en memoria. El carga-dor de clases sabe donde cada clase que se carga esta localizada en disco.El metodo getResource usa el cargador de clases del objeto Class paradeterminar el lugar de un recurso, tal como una archivo de imagen. Eneste ejemplo, el archivo de imagen esta guardado en el mismo lugar queel archivo VentanaLabel.class. La tecnica descrita permite a una aplica-cion cargar archivos de imagen desde localidades que son relativas al archivoVentanaLabel.class en el disco.

Como se puede apreciar en la lınea 30, al crear un JLabel se puede pasaren el constructor una referencia tipo Icon para que la etiqueta este compuestade texto e imagen. Tambien es posible, que despues de haber creado el objeto,se agregue la imagen, usando el metodo setIcon, como se hace en la lınea28.

Las lıneas 39 y 40 usan los metodos setHorizontalTextPosition ysetVerticalTextPosition de la clase JLabel para acomodar el texto hori-zontalmente y verticalmente respectivamente. Las constantes empleadas conestos metodos, que se encuentran definidas en la clase SwingConstants sedescriben a continuacion:

Posicion HorizontalSwingConstants.LEFT Texto a la izquierda.

SwingConstants.CENTER Texto en el centro.SwingConstants.RIGHT Texto a la derecha.

Posicion VerticalSwingConstants.TOP Texto en la cima

SwingConstants.CENTER Texto en el centro.SwingConstants.BOTTOM Texto al fondo.

3.4. Campos de texto y manejo de eventos

con clases anidadas

Normalmente, un usuario interactua con una aplicacion GUI para indicarlas tareas que la aplicacion debera hacer. Cuando el usuario interactua con un

Page 43: notasGUI

3.4 Campos de texto y eventos 43

componente GUI, la interaccion —conocida como un evento —conduce alprograma a realizar una tarea. Algunos eventos comunes que podrıan causarque una aplicacion haga una tarea incluyen el pulsado de un boton, el tecleadoen un campo de texto, la seleccion de un elemento de un menu, el cerradode una ventana y el movimiento del raton. El codigo que realiza una tareaen respuesta a un evento es llamado un manejador de eventos y todo elproceso de respuesta a eventos es conocido como manejo de eventos.

Se revisan en esta seccion dos nuevos componentes GUI que pueden ge-nerar eventos —JTextField y JPasswordField del paquete java.swing. Laclase JTextField extiende la clase JTextComponent del paquete javax.swing-.text, la cual proporciona varias capacidades comunes a los componentesSwing basados en texto. La clase JPasswordField extiende a JTextField yagrega varios metodos que son especıficos para procesar contrasenas. Cadauno de estos componentes es una area de una sola lınea en el cual el usua-rio puede ingresar texto usando el teclado. Las aplicaciones pueden tambienmostrar texto en un JTextField. Un JPasswordField muestra que caracte-res han sido tecleado conforme el usuario los ha ingresado, pero esconde elcaracter actual con un caracter eco, asumiendo que estos representan unacontrasena que solo deberıa ser conocida por el usuario.

Cuando el usuario teclea datos en un JTextField o en un JPasswordField,y despues presiona Intro, un evento ocurre. El siguiente ejemplo muestra co-mo un programa puede realizar una tarea en respuesta a ese evento. Lastecnicas mostradas en el ejemplo son aplicables a todos los componentesGUI que generan eventos.

La aplicacion siguiente usa las clases JTextField y JPasswordField paracrear y manipular cuatro campos de texto. Cuando el usuario teclea en unode los campos de texto, y presiona Intro, la aplicacion muestra un cuadrode dialogo conteniendo el texto que el usuario tecleo. El usuario solo puedeteclear en el campo de texto que este “en foco”. Un componente recibe elfoco cuando el usuario pulsa en el componente. Esto es importante, porqueel campo de texto con el foco es el que genera un evento cuando el usua-rio presiona Intro. En este ejemplo, cuando el usuario presiona Intro en elJPasswordField, la contrasena es revelada.

1 // VentanaTextField.java

2 // Mostrando la clase JTextField.

3

4 import java.awt.FlowLayout;

5 import java.awt.event.ActionListener;

Page 44: notasGUI

44 Componentes GUI

6 import java.awt.event.ActionEvent;

7 import javax.swing.JFrame;

8 import javax.swing.JTextField;

9 import javax.swing.JPasswordField;

10 import javax.swing.JOptionPane;

11

12 public class VentanaTextField extends JFrame {

13

14 private JTextField campoTexto1; // campo de texto con el tama~no dado

15 private JTextField campoTexto2; // campo de texto construido con texto

16 private JTextField campoTexto3; // campo de texto con texto y tama~no

17 private JPasswordField campoContra; // campo de contrase~na con texto

18

19 // constructor VentanaTextField que agrega JTextFields al JFrame

20 public VentanaTextField() {

21 super( "Probando JTextField y JPasswordField" );

22 setLayout( new FlowLayout() ); // poner el dise~nador de ventana

23

24 // construir campo de texto con 10 columnas

25 campoTexto1 = new JTextField( 10 );

26 add( campoTexto1 ); // agregar campoTexto1 al JFrame

27

28 // construir campo de texto con texto por defecto

29 campoTexto2 = new JTextField( "Ingresar texto aquı" );

30 add( campoTexto2 ); // agregar campoTexto2 al JFrame

31

32 // construir campo de texto con texto por defecto y 21 columnas

33 campoTexto3 = new JTextField( "Campo de texto no editable", 21 );

34 campoTexto3.setEditable( false ); // deshabilitar la edicion

35 add( campoTexto3 ); // agregar campoTexto3 al JFrame

36

37 // construir campo de contrase~na con texto por defecto

38 campoContra = new JPasswordField( "Texto oculto" );

39 add( campoContra ); // agregar campoContra al JFrame

40

41 // registrar manejadores de eventos

42 TextFieldHandler manejador = new TextFieldHandler();

43 campoTexto1.addActionListener( manejador );

44 campoTexto2.addActionListener( manejador );

45 campoTexto3.addActionListener( manejador );

46 campoContra.addActionListener( manejador );

47 } // fin del constructor VentanaTextField

48

49 // clase privada interna para manejo de eventos

50 private class TextFieldHandler implements ActionListener {

Page 45: notasGUI

3.4 Campos de texto y eventos 45

51

52 // procesar eventos de campos de texto

53 public void actionPerformed( ActionEvent evento ) {

54

55 String cadena = ""; // declarar un String para mostrar

56

57 // usuario presiono Intro en JTextField campoTexto1

58 if ( evento.getSource() == campoTexto1 )

59 cadena = String.format( "campoTexto1: %s",

60 evento.getActionCommand() );

61

62 // usuario presiono Intro en JTextField campoTexto2

63 else if ( evento.getSource() == campoTexto2 )

64 cadena = String.format( "campoTexto2: %s",

65 evento.getActionCommand() );

66

67 // usuario presiono Intro en JTextField campoTexto3

68 else if ( evento.getSource() == campoTexto3 )

69 cadena = String.format( "campoTexto3: %s",

70 evento.getActionCommand() );

71

72 // usuario presiono Intro en campoContra

73 else if ( evento.getSource() == campoContra )

74 cadena = String.format( "campoContra: %s",

75 new String( campoContra.getPassword() ) );

76

77 // mostrar el contenido de JTextField

78 JOptionPane.showMessageDialog( null, cadena );

79 } // fin del metodo actionPerformed

80 } // fin de la clase interna TextFieldHandler

81 } // fin de la clase VentanaTextField

1 // PruebaTextField.java

2 // Probando VentanaTextField.

3

4 import javax.swing.JFrame;

5

6 public class PruebaTextField {

7

8 public static void main( String args[] ) {

9 VentanaTextField ventanaTextField = new VentanaTextField();

10 ventanaTextField.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaTextField.setSize( 350, 100 ); // fijar tama~no de la ventana

12 ventanaTextField.setVisible( true ); // mostrar ventana

13 } // fin main

14 } // fin de la clase PruebaTextField

Page 46: notasGUI

46 Componentes GUI

Creacion de la GUI. La lınea 22 pone el diseno de VentanaTextField

a FlowLayout. La lınea 25 crea campoTexto1 con 10 columnas de texto. Elancho en pıxeles de una columna de texto esta determinado por el anchopromedio de un caracter en el campo de texto de la fuente actual. Cuandoel texto es mostrado en un campo de texto y el texto es mas ancho que elcampo de texto, una porcion del texto en el lado derecho no es visible. Si seesta tecleando en un campo de texto y el cursor alcanza el lado derecho delcampo de texto, el texto del lado izquierdo es recorrido hacia alla y no severa mas. El usuario puede usar las teclas de navegacion izquierda y derechapara moverse a traves del texto completo aun si el texto entero no es visibleen un momento. La lınea 26 agrega campoTexto1 al JFrame.

La lınea 29 crea campoTexto2 con el texto inicial “Ingresar texto aquı”para ser mostrado en el campo de texto. El ancho del campo de texto esta de-terminado por el ancho del texto indicado en el constructor. La lınea 30 loagrega al JFrame.

La lınea 33 crea campoTexto3 y llama al constructor JTextField condos argumentos —el texto “Campo de texto no editable” a mostrar y elnumero de columnas (21). La lınea 34 usa el metodo setEditable (heredadaa JTextField desde la clase JTextComponent) para hacer el campo de textono editable. En la lınea 35 se agrega al JFrame.

La lınea 38 crea campoContrase~na con el texto “Texto oculto” paramostrarlo en el campo de texto. Cuando se ejecuta la aplicacion, observarque el texto es mostrado como una cadena de asteriscos. La lınea 39 lo agregaal JFrame.

Pasos para manejar eventos. El ejemplo debera mostrar un cuadro demensaje conteniendo el texto desde el campo cuando el usuario presiona Introen aquel campo de texto. Antes de que una aplicacion pueda responder a unevento para un componente GUI particular, el programador debera hacervarios pasos de codificacion:

1. Crear una clase que represente al manejador de evento.

2. Implementar una interfaz apropiada, conocida como interfaz recep-tora del evento, en la clase del primer paso.

3. Indicar que un objeto de la clase desde los pasos 1 y 2 debera sernotificado cuando el evento ocurrra. Esto es conocido como registrarel manejador de evento.

Page 47: notasGUI

3.4 Campos de texto y eventos 47

Uso de clases anidadas para manejo de eventos. Todas las clases vis-tas previamente son llamadas clases de nivel superior —esto es, las clasesno fueron declaradas dentro de otra clase. Java permite declarar clases den-tro de otra —estas clases son llamadas clases anidadas. Las clases anidadaspueden ser static o no. Las clases anidadas no static son llamadas clasesanidadas y son frecuentemente empleadas para manejar eventos.

Una clase interna permite acceso directamente a las variables y metodosde su clase de nivel superior, aun si ellos son private.

Antes de que un objeto de una clase interna pueda ser creado, debera ha-ber primero un objeto de la clase de nivel superior que contenga la claseinterna. Esto es requerido porque un objeto de la clase interna implıcitamen-te tiene una referencia a un objeto de su clase de nivel superior. Hay unarelacion especial entre estos objetos —al objeto de la clase interna se le per-mite accesar directamente todas las variables de instancia y metodos de laclase externa. Una clase anidada que es static no requiere un objeto de laclase de nivel superior y no tiene implıcitamente una referencia a un objetode la clase de nivel superior.

El manejo de evento en este ejemplo es hecho por un objeto de la clase in-terna private TextFieldHandler en las lıneas 50–81. Esta clase es privateporque esta sera usada solamente para crear manejadores de eventos para loscampos de texto en la clase de nivel superior VentanaTextField. Al igual quecon otros miembros de una clase, las clases internas pueden ser declaradaspublic, protected o private.

Los componentes GUI pueden generar una variedad de eventos en res-puesta a las interacciones del usuario. Cada evento esta representado poruna clase y puede ser procesado solamente por el tipo apropiado de mane-jador de eventos. Los eventos que un componente GUI soporta estan des-critos en la documentacion API de Java. Cuando el usuario presiona Introen un JTextField o un JPasswordField, el componente GUI genera unActionEvent (paquete java.awt.event). Tal evento es procesado por un ob-jeto que implementa la interfaz ActionListener (paquete java.awt.event).Como JPasswordField es una subclase de JTextField, JPasswordField so-porta los mismos eventos.

Para preparar el manejo de los eventos, la clase interna TextFieldHandlerimplementa la interfaz ActionListener y declara el unico metodo en la in-terfaz —actionPerformed (lıneas 50–80). Este metodo indica las tareas arealizar cuando un evento ActionEvent suceda.

Page 48: notasGUI

48 Componentes GUI

Registro del manejador de eventos En el constructor VentanaTextField,la lınea 42 crea un objeto TextFieldHandler y lo asigna a la variable maneja-dor. El metodo actionPerformed del objeto sera llamado automaticamentecuando el usuario presione Intro en cualquiera de los campos de texto GUI.Sin embargo, antes de que esto pueda ocurrir, el programa debera regis-trar este objeto como el manejador de eventos para cada campo de texto.Las lıneas 43–46 son las sentencias de registro de eventos que indican quemanejador se empleara con los tres JTextField y el JPasswordField. Laaplicacion llama al metodo addActionListener de la clase JTextField, pa-ra registrar el manejador de eventos para cada componente. Este metodorecibe como su argumento un objeto actionListener, el cual puede ser unobjeto de cualquier clase que implemente ActionListener. Cuando el usua-rio presiona Intro en cualquiera de estos cuatro campos de textos, el metodoactionPerformed (lıneas 53–79) de la clase TextFieldHandler es llamadopara manejar el evento. Si un manejador de evento no esta registrado paraun campo de texto particular, el evento que ocurre cuando el usuario pre-siona Intro en aquel campo de texto es consumido —esto es, el evento essimplemente ignorado por la aplicacion.

Metodo actionPerformed En el ejemplo, se esta usando un solo objetomanejador de eventos, con el metodo actionPerformed, para manejar loseventos generados por los cuatro campos de texto. Como se quiere mostrarel nombre de cada variable de instancia del campo de texto donde se generael evento, se debe determinar cual es el campo de texto que genero el eventocada vez que actionPerformed es llamado. El componente GUI con el cualel usuario interactuo es la fuente del evento. Para el ejemplo, la fuentedel evento es uno de los campos de texto o el de la contrasena. Cuando elusuario presiona Intro mientras uno de estos componentes tiene el foco, elsistema crea un objeto unico ActionEvent que contiene informacion acercadel evento que ha ocurrido, tal como la fuente del evento y el texto en elcampo de texto. El sistema entonces pasa este objeto ActionEvent en unallamada al metodo receptor de eventos actionPerformed. En el ejemplo, semuestra algo de esa informacion en un cuadro de mensaje.

El metodo getSource de ActionEvent, llamado en las lıneas 58, 63, 68 y75, regresa una referencia a la fuente del evento. La condicion en la lınea 58pregunta, “¿es la fuente del evento campoTexto1?”. Esta condicion comparalas referencias a cada lado del operador == para determinar si ellas se refieren

Page 49: notasGUI

3.5 Tipos de eventos e interfaces receptoras 49

al mismo objeto. Si ellas se refieren a campoTexto1, entonces el programasabra que el usuario presiono Intro en campoTexto1 y en las lıneas 59–60se crea un String conteniendo el mensaje que la lınea 78 mostrara en uncuadro de mensaje. La lınea 60 usa el metodo getActionCommand de la claseActionEvent para obtener el texto que el usuario tecleo en el campo de textoque genero el evento.

La clase PruebaTextField contiene el metodo main que ejecuta su apli-cacion y muestra un objeto de la clase VentanaTextField. Cuando la apli-cacion es ejecutada, observar que aun el campo no editable JTextField

(campoTexto3) puede generar un ActionEvent. Para probarlo, pulsar el cam-po de texto para darle el foco, y presionar Intro. Tambien observar que eltexto actual de la contrasena es mostrado cuando el usuario presiona Introen el campo JPasswordField.

3.5. Tipos de eventos e interfaces receptoras

Varios tipos diferentes de eventos pueden ocurrir cuando el usuario inter-actua con una GUI. La informacion acerca de cualquier evento GUI que ocu-rra es guardada en un objeto de una clase que extiende AWTEvent. La figura3.1 muestra una jerarquıa conteniendo varias clases de eventos del paque-te java.awt.event. Estos tipos de eventos son usados con los componentesAWT y Swing. Los tipos de eventos adicionales que son especıficos a los com-ponentes GUI tipo Swing estan declarados en el paquete javax.swing.event.

Las tres partes para el mecanismo de manejo de eventos son: la fuentedel evento, el objeto evento y el receptor del evento. La fuente del eventoes el componente GUI particular con el cual el usuario interactua. El objetoevento encapsula informacion acerca del evento que ocurrio, tal como unareferencia a la fuente del evento y cualquier informacion especıfica que podrıaser requerida por el receptor de eventos para manejar el evento. El receptordel evento es un objeto que es notificado por la fuente del evento cuando elevento ocurre; en efecto, este “escucha” por un evento, y uno de sus metodosse ejecuta en respuesta al evento. Un metodo del receptor de eventos recibeun objeto evento cuando el receptor de eventos es notificado del evento. Elreceptor del evento entonces usa el objeto evento para responder al evento.El modelo de manejo de eventos descrito es conocido como el modelo dedelegacion de eventos— un procesamiento de eventos es delegado a unobjeto particular (el receptor de eventos) en la aplicacion.

Page 50: notasGUI

50 Componentes GUI

Figura 3.1: Algunas clases de eventos del paquete java.awt.event.

Page 51: notasGUI

3.6 Como trabaja el manejador de eventos 51

Para cada tipo de objeto-evento, hay tıpicamente una interfaz receptorade eventos correspondiente. Un receptor de eventos para un evento GUI es unobjeto de una clase que implementa uno o mas de las interfaces receptoras deeventos de los paquetes java.awt.event o javax.swing.event. Varios delos tipos receptores de eventos son comunes a componentes Swing y compo-nentes AWT. Tales tipos estan declarados en el paquete java.awt.event, yalgunos estan mostrados en la figura 3.2. Los tipos adicionales de receptoresde eventos que son especıficos para componentes Swing estan declarados enel paquete javax.swing.event.

Cada interfaz receptora de eventos indica uno o mas metodos de manejode eventos que debera ser declarado en la clase que implementa la interfaz.Cualquier clase que implemente una interfaz debera declarar todos los meto-dos abstract de la interfaz; de otra forma, la clase es una clase abstract yno puede ser usada para crear objetos.

3.6. Como trabaja el manejador de eventos

Se comenta como el mecanismo de manejo de eventos trabaja, usando elejemplo de la seccion 3.4 para la variable de instancia campoTexto1 de laclase VentanaTextField.

1. ¿Como fue registrado el manejador de eventos? Mediante el registro deeventos hecho en las lıneas 43–46 de la apalicacion.

2. ¿Como sabe el componente GUI que debe llamar a actionPerformed

en vez de otro metodo manejador?

Registrando eventos. Cada JComponent tiene una variable de instanciallamada listenerList que refiere a un objeto de la clase EventListenerListdel paquete javax.swing.event. Cada objeto de una subclase de JComponentmantiene una referencia a todos sus receptores registrados en la listenerList.

Cuando la lınea 43 de la clase VentanaTextField

campoTexto1.addActionListener( manejador );

se ejecuta una nueva entrada conteniendo una referencia al objeto manejador

que es puesta en la lista listenerList de campoTexto1. Empleando este me-canismo, cada componente GUI ligero mantiene su propia lista de receptoresque fueron registrados para manejar los eventos del componente.

Page 52: notasGUI

52 Componentes GUI

Figura 3.2: Algunas interfaces receptoras de eventos del paquetejava.awt.event.

Page 53: notasGUI

3.7 JButton 53

El tipo del receptor de eventos es importante para que el componenteGUI sepa llamar a actionPerformed en vez de otro metodo. Cada compo-nente GUI soporta varios tipos de eventos, incluyendo eventos del raton,eventos del teclado y otros. Cuando un evento ocurre, el evento es despa-chado solamente a los receptores de eventos del tipo apropiado. Despachares simplemente el proceso por el cual el componente GUI llama un metodode manejo de eventos para cada uno de sus receptores que estan registradospara un tipo de evento particular que ocurrio.

Cada tipo de evento tiene una o mas interfaces receptoras de eventoscorrespondientes. Por ejemplo, eventos ActionEvent son manejados por lainterfaz ActionListener, eventos MouseEvent son manejados por las in-terfaces MouseListener y MouseMotionListener, y eventos KeyEvent sonmanejados por la interfaz KeyListener. Cuando un evento ocurre, el compo-nente GUI recibe (desde la JVM) un ID de evento unico indicando el tipode evento. El componente GUI usa el ID para decidir el tipo de receptor alcual el evento debera ser despachado y para decidir cual metodo llamar encada objeto receptor. Para un evento ActionEvent, el evento es despacha-do para cada metodo actionPerformed de ActionListener registrado (elunico metodo en la interfaz ActionListener).

3.7. JButton

Un boton es un componente que el usuario pulsa para lanzar una ac-cion especıfica. Una aplicacion de Java puede usar varios tipos de botones,incluyendo botones de pulsacion o command button, de seleccion o checkboxbutton, de interruptor o toggle button y de radio radio button. La figura 3.3muestra la jerarquıa de herencia de los botones revisados en este capıtulo. Co-mo se puede ver, todos los tipos de botones son subclases de AbstractButtondel paquete javax.swing, la cual declara las caracterısticas comunes de losbotones Swing.

Un boton de pulsacion genera un evento ActionEvent cuando el usuariopulsa el boton. Los botones de pulsacion son creados con la clase JButton.El texto en la cara de un JButton es llamada etiqueta de boton. UnaGUI puede tener varios JButton, pero cada etiqueta de boton tıpicamentedebera ser unica en la porcion de la GUI que es mostrada.

La siguiente aplicacion crea dos JButtons y muestra que los JButton

soportan el despliegue de Icons. El manejo de eventos para los botones es

Page 54: notasGUI

54 Componentes GUI

Figura 3.3: Jerarquıa de los botones Swing.

realizado por una sola instancia de la clase interna ManejadorBoton (lıneas39–47).

1 // VentanaBoton.java

2 // Creacion de JButtons.

3 import java.awt.FlowLayout;

4 import java.awt.event.ActionListener;

5 import java.awt.event.ActionEvent;

6 import javax.swing.JFrame;

7 import javax.swing.JButton;

8 import javax.swing.Icon;

9 import javax.swing.ImageIcon;

10 import javax.swing.JOptionPane;

11

12 public class VentanaBoton extends JFrame {

13

14 private JButton jBotonPlano; // boton con solo texto

15 private JButton jBotonAdornado; // boton con iconos

16

17 // VentanaBoton agrega JButtons al JFrame

18 public VentanaBoton() {

19

20 super( "Probando Botones" );

21 setLayout( new FlowLayout() ); // poner dise~no de ventana

22

23 jBotonPlano = new JButton( "Boton Plano" ); // boton con texto

24 add( jBotonPlano ); // agregar jBotonPlano a JFrame

25

26 Icon bug1 = new ImageIcon(getClass().getResource("gnome-gnibbles.png") );

Page 55: notasGUI

3.7 JButton 55

27 Icon bug2 = new ImageIcon(getClass().getResource("gnome-robots.png"));

28 jBotonAdornado = new JButton( "Boton Adornado", bug1 ); // poner icon

29 jBotonAdornado.setRolloverIcon( bug2 ); // poner icon rotacion

30 add( jBotonAdornado ); // agregar jBotonAdornado a JFrame

31

32 // crear nuevo ManejadorBoton para manejar eventos del boton

33 ManejadorBoton handler = new ManejadorBoton();

34 jBotonAdornado.addActionListener( handler );

35 jBotonPlano.addActionListener( handler );

36 } // fin del constructor VentanaBoton

37

38 // clase interna para el manejo de eventos del boton

39 private class ManejadorBoton implements ActionListener {

40

41 // manejar evento del boton

42 public void actionPerformed( ActionEvent event ) {

43

44 JOptionPane.showMessageDialog( VentanaBoton.this, String.format(

45 "Ha presionado: %s", event.getActionCommand() ) );

46 } // fin del metodo actionPerformed

47 } // fin de la clase interna privada ManejadorBoton

48 } // fin de la clase VentanaBoton

Las lıneas 14–15 declaran las variables JButton jBotonPlano y jBoton-Adornado. Los correspondientes objetos son instanciados en el constructor.La lınea 23 crea jBotonPlano con la etiqueta de boton “Boton Plano”. Lalınea 24 agrega el boton al JFrame. Un JButton puede desplegar un Icon. Pa-ra dar al usuario un nivel extra de interaccion visual con la GUI, un JButton

puede tambien tener un Icon de rotacion—un Icon que es mostrado cuandoel usuario pone el raton sobre el boton. Las lıneas 26–27 crean dos objetosImageIcon que representan el icono por defecto y el de rotacion para el botonque es creado en la lınea 28. La lınea 28 crea jBotonAdornado con el tex-to “Boton Adornado” y el icono bug1. Por defecto, el texto es mostrado ala derecha de la imagen. La lınea 29 usa setRolloverIcon, heredada de laclase AbstractButton, para indicar la imagen mostrada en el boton cuandoel usuario posiciona el raton encima de este. La lınea 30 agrega el boton alJFrame.

Los JButtons, como los JTextFields, generan eventos ActionEvent quepueden ser procesados por cualquier objeto ActionListener. Las lıneas 33–35 crean un objeto de la clase private ManejadorBoton y lo registran comoel manejador de evento para cada JButton. La clase ManejadorBoton, en laslıneas 39–47, declara actionPerformed para mostrar un cuadro de dialogo

Page 56: notasGUI

56 Componentes GUI

conteniendo la etiqueta para el boton que el usuario presiono. Para un eventoJButton, el metodo getActionCommand regresa la etiqueta sobre el boton.

Cuando se ejecuta la aplicacion y se pulsa sobre uno de sus botones, seobserva que el cuadro de dialogo aparece centrado sobre la ventana de laaplicacion. Esto ocurre porque la llamada al metodo showMessageDialog

de la clase JOptionPane en las lıneas 44–45 usa VentanaBoton.this en vezde null como primer argumento. Cuando este argumento no es null, es-te representa al componente padre que llama al cuadro de dialogo, en es-te caso la ventana de la aplicacion es el componente padre, y permite quedialogo este centrado sobre el componente cuando el dialogo es mostrado.VentanaBoton.this representa la referencia del objeto de la clase de nivelsuperior VentanaBoton.

Cuando la palabra clave this es usada en una clase interna, esta se re-fiere al objeto actual de la clase interna que se esta manipulando. Un meto-do de una clase interna puede usar su objeto this de la clase externa siprecede a this con el nombre de la clase externa y un punto, como enVentanaBoton.this en la lınea 44 del codigo previo.

El codigo que crea y usa un VentanaBoton es similar a los vistos previa-mente. Se muestra a continuacion.

1 // PruebaBoton.java

2 // Probando VentanaBoton.

3 import javax.swing.JFrame;

4

5 public class PruebaBoton {

6

7 public static void main( String args[] ) {

8

9 VentanaBoton ventanaBoton = new VentanaBoton(); // crear VentanaBoton

10 ventanaBoton.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaBoton.setSize( 275, 130 ); // fijar tama~no de la ventana

12 ventanaBoton.setVisible( true ); // mostrar la ventana

13 } // fin de main

14 } // fin de la clase PruebaBoton

3.8. Botones que mantienen estado

Los componentes GUI de Swing contienen tres tipos de botones de es-tado—JToggleButton, JCheckbox y JRadioButton—que tienen valores deencendido/apagado o verdadero/falso. Las clases JCheckBox y JRadioButton

Page 57: notasGUI

3.8 Botones que mantienen estado 57

son subclases de JToggleButton ver figura 3.3. Un JRadioButton es diferen-te de un JCheckbox ya que normalmente varios JRadioButton son agrupadosjuntos, y son mutuamente excluyentes—solamente uno en el grupo puede serseleccionado a la vez.

3.8.1. JCheckBox

La aplicacion siguiente usa dos objetos JCheckBox para seleccionar elestilo deseado para la fuente del texto mostrado en un JTextField. Cuandose selecciona, se aplica un estilo negrita y el otro un estilo italica. Si ambos sonseleccionados, el estilo de la fuente es negrita e italica. Cuando la aplicacioninicialmente se ejecuta, ninguno de los dos JCheckbox esta marcado, es decir,ambos estan en falso, por lo que la fuente es plana.

1 // VentanaCheckBox.java

2 // Creacion de botones JCheckBox.

3 import java.awt.FlowLayout;

4 import java.awt.Font;

5 import java.awt.event.ItemListener;

6 import java.awt.event.ItemEvent;

7 import javax.swing.JFrame;

8 import javax.swing.JTextField;

9 import javax.swing.JCheckBox;

10

11 public class VentanaCheckBox extends JFrame {

12

13 private JTextField campoTexto; // muestra texto en fuentes cambiantes

14 private JCheckBox negritaJCheckBox; // para activar/desactivar negrita

15 private JCheckBox italicaJCheckBox; // para activar/desactivar italica

16

17 // constructor VentanaCheckBox agrega JCheckBoxes a JFrame

18 public VentanaCheckBox() {

19

20 super( "Prueba JCheckBox" );

21 setLayout( new FlowLayout() ); // poner dise~no ventana

22

23 // configurar JTextField y su fuente

24 campoTexto = new JTextField( "Observar cambio de estilo de la fuente", 20 );

25 campoTexto.setFont( new Font( "Serif", Font.PLAIN, 14 ) );

26 add( campoTexto ); // agregar campoTexto a JFrame

27

28 negritaJCheckBox = new JCheckBox( "Negrita" ); // crear negrita

29 italicaJCheckBox = new JCheckBox( "Italica" ); // crear italica

Page 58: notasGUI

58 Componentes GUI

30 add( negritaJCheckBox ); // agregar seleccion negrita a JFrame

31 add( italicaJCheckBox ); // agregar seleccion italica a JFrame

32

33 // registrar receptores para los JCheckBoxes

34 ManejadorBotonSel manejador = new ManejadorBotonSel();

35 negritaJCheckBox.addItemListener( manejador );

36 italicaJCheckBox.addItemListener( manejador );

37 } // fin del constructor VentanaCheckBox

38

39 // clase privada interna para manejar eventos ItemListener

40 private class ManejadorBotonSel implements ItemListener {

41

42 private int valNegrita = Font.PLAIN; // controla estilo negrita

43 private int valItalica = Font.PLAIN; // controla estilo italica

44

45 // responder a eventos checkbox

46 public void itemStateChanged( ItemEvent event ) {

47

48 // procesar eventos seleccion negrita

49 if ( event.getSource() == negritaJCheckBox )

50 valNegrita =

51 negritaJCheckBox.isSelected() ? Font.BOLD : Font.PLAIN;

52

53 // procesar eventos seleccion italica

54 if ( event.getSource() == italicaJCheckBox )

55 valItalica =

56 italicaJCheckBox.isSelected() ? Font.ITALIC : Font.PLAIN;

57

58 // poner la fuente del campo de texto

59 campoTexto.setFont(

60 new Font( "Serif", valNegrita + valItalica, 14 ) );

61 } // fin metodo itemStateChaged

62 } // fin de la clase privada interna ManejadorBotonSel

63 } // fin de la clase VentanaCheckBox

Despues de que el JTextField es creado e inicializado en la lınea 24, lalınea 25 usa el metodo setFont, heredado por JTextField indirectamen-te de la clase Component, para poner la fuente del JTextField a un nuevoobjeto de la clase Font, del paquete java.awt. La nueva fuente es inicializa-da con “Serif”, un nombre de fuente generica representando a una fuentecomo Times y que es soportada en todas las plataformas Java, con estiloFont.PLAIN y tamano de 14 puntos. Enseguida, las lıneas 28–29 crean dosobjetos JCheckBox. Las cadenas pasadas al constructor de JCheckBox es laetiqueta del boton de seleccion que aparece a la derecha por defecto.

Page 59: notasGUI

3.8 Botones que mantienen estado 59

Cuando el usuario pulsa un JCheckBox, un evento ItemEvent ocurre.Este evento puede ser manejado por un objeto ItemListener, el cual de-bera implementar el metodo itemStateChanged. En el ejemplo, el mane-jador del evento es realizado por una instancia de la clase privada internaManejadorBotonSel y registrado con el metodo addItemListener como elreceptor para ambos objetos JCheckBox.

Las lıneas 42–43 declaran variables de instancia para la clase internaManejadorBotonSel. Estas variables representan el estilo de la fuente para eltexto mostrado en el JTextField. Inicialmente ambas son Font.PLAIN paraindicar que la fuente no es negrita ni italica. El metodo itemStateChanged,lıneas 46–61, es llamado cuando cuando el usuario pulsa en el JCheckBox denegritas o italicas. El metodo usa event.getSource() para determinar cualJCheckBox fue pulsado por el usuario. Si fue negritaJCheckBox, la lınea 51usa el metodo isSelected de JCheckBox para determinar si el JCheckBoxesta seleccionado. Si el boton de seleccion esta seleccionado, a la variable localvalNegrita se le asigna Font.BOLD; de otra forma, se le asigna Font.PLAIN.Una sentencia similar se ejecuta si el usuario pulsa italicaJCheckBox. SiitalicaJCheckBox esta seleccionado, a la variable local valItalica se leasigna Font.ITALICA; de otra forma, se le asigna Font.PLAIN. Las lıneas59–60 cambian la fuente del JTextField, usando el mismo nombre de fuentey tamano en puntos. La suma de valNegrita y valItalica representa elnuevo estilo de la fuente del JTextField. Cada una de las constantes deFont representan un valor unico. Font.PLAIN tiene el valor de 0, por lotanto si valNegrita y valItalica estan puestas a Font.PLAIN, la fuentetendra el estilo simple. Si uno de los valores de las variables es Font.BOLD

o Font.ITALIC, la fuente sera negrita o italica. Si ambas tienen un valordiferente de Font.PLAIN, entonces la fuente sera negrita e italica.

Relacion entre la clase interna y su clase de nivel superior Se puedeobservar que la clase ManejadorBotonSel usa la variable negritaJCheckBox,lıneas 49 y 51, la variable italicaJCheckbox, lıneas 54 y 56 y campoTexto apesas de que estas variables no estan declaradas en la clase interna. Una claseinterna tiene una relacion especial con su clase de nivel superior—a la claseinterna se le permite acceder directamente todas las variables y metodos deinstancia de la clase de nivel superior. El metodo itemStateChanged, lıneas46–61, de la clase ManejadorBotonSel usa esta relacion para determinar cualJCheckBox es la fuente del evento, para determinar el estado del JCheckBox

Page 60: notasGUI

60 Componentes GUI

y para poner la fuente de campoTexto. Se debe observar que ninguna partedel codigo de la clase interna ManejadorBotonSel requiere una referencia alobjeto de la clase de nivel superior.

La clase PruebaCheckBox contiene el metodo principal que ejecuta laaplicacion VentanaCheckBox.

1 // PruebaCheckBox.java

2 // Testing VentanaCheckBox.

3 import javax.swing.JFrame;

4

5 public class PruebaCheckBox {

6

7 public static void main( String args[] ) {

8

9 VentanaCheckBox ventanaCheckBox = new VentanaCheckBox();

10 ventanaCheckBox.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaCheckBox.setSize( 300, 100 ); // poner tama~no ventana

12 ventanaCheckBox.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase PruebaCheckBox

3.8.2. JRadioButton

Los botones de radio, declarados con la clase JRadioButton, son si-milares a los JCheckBox en el sentido de que estos tienen dos estados—seleccionado y deseleccionado. Sin embargo, los botones de radio normal-mente aparecen como grupo en el cual solamente un boton puede ser selec-cionado a la vez. Seleccionando un boton de radio diferente fuerza al resto aser deseleccionados. Los botones de radio son usados para representar opcio-nes mutuamente excluyentes. La relacion logica entre botones de radioes mantenida por un objeto ButtonGroup del paquete javax.swing, el cualpor sı mismo no es un componente GUI. Un objeto ButtonGroup organiza ungrupo de botones y por si mismo no es mostrado en la interfaz del usuario.Sin embargo, los objetos JRadioButton individuales del grupo son mostradosen la GUI.

La siguiente aplicacion es similar a la del ejemplo usando JCheckBox. Elusuario puede alterar el estilo de la fuente del JTextField. La aplicacion usabotones de radio que permiten solamente un estilo individual de fuente, enel grupo para ser seleccionado a la vez.

1 // VentanaRadioButton.java

Page 61: notasGUI

3.8 Botones que mantienen estado 61

2 // Creando botones de radio usando ButtonGroup y JRadioButton.

3 import java.awt.FlowLayout;

4 import java.awt.Font;

5 import java.awt.event.ItemListener;

6 import java.awt.event.ItemEvent;

7 import javax.swing.JFrame;

8 import javax.swing.JTextField;

9 import javax.swing.JRadioButton;

10 import javax.swing.ButtonGroup;

11

12 public class VentanaRadioButton extends JFrame {

13

14 private JTextField campoTexto; // usdo para mostrar los cambios de fuente

15 private Font fuentePlana; // fuente para texto plano

16 private Font fuenteNegrita; // fuente para texto negrita

17 private Font fuenteItalica; // fuente para texto italica

18 private Font fuenteNegritaItalica; // fuente para texto negrita e italica

19 private JRadioButton planoJRadioButton; // selecciona texto plano

20 private JRadioButton negritaJRadioButton; // selecciona texto negrita

21 private JRadioButton italicaJRadioButton; // selecciona texto italica

22 private JRadioButton negritaItalicaJRadioButton; // negrita e italica

23 private ButtonGroup grupoRadio; // buttongroup para los botones radio

24

25 // Constructor VentanaRadioButton que agrega JRadioButtons a JFrame

26 public VentanaRadioButton() {

27

28 super( "Prueba RadioButton" );

29 setLayout( new FlowLayout() ); // poner dise~no ventana

30

31 campoTexto = new JTextField( "Observar cambio de estilo de la fuente", 25 );

32 add( campoTexto ); // agregar campoTexto a JFrame

33

34 // crear botones de radio

35 planoJRadioButton = new JRadioButton( "Plano", true );

36 negritaJRadioButton = new JRadioButton( "Negrita", false );

37 italicaJRadioButton = new JRadioButton( "Italica", false );

38 negritaItalicaJRadioButton = new JRadioButton( "Negrita//Italica", false );

39 add( planoJRadioButton ); // agregar boton plano a JFrame

40 add( negritaJRadioButton ); // agregar boton negrita a JFrame

41 add( italicaJRadioButton ); // agregar boton italica a JFrame

42 add( negritaItalicaJRadioButton ); // agregar boton negrita e italica

43

44 // crear relacion logica entre JRadioButtons

45 grupoRadio = new ButtonGroup(); // crear ButtonGroup

46 grupoRadio.add( planoJRadioButton ); // agregar plano al grupo

Page 62: notasGUI

62 Componentes GUI

47 grupoRadio.add( negritaJRadioButton ); // agregar negrita al grupo

48 grupoRadio.add( italicaJRadioButton ); // agregar italica al grupo

49 grupoRadio.add( negritaItalicaJRadioButton ); // agregar negrita e italica

50

51 // crear objetos fuente

52 fuentePlana = new Font( "Serif", Font.PLAIN, 14 );

53 fuenteNegrita = new Font( "Serif", Font.BOLD, 14 );

54 fuenteItalica = new Font( "Serif", Font.ITALIC, 14 );

55 fuenteNegritaItalica = new Font( "Serif", Font.BOLD + Font.ITALIC, 14 );

56 campoTexto.setFont( fuentePlana ); // poner fuente inicial en plano

57

58 // registrar manejadores de eventos para JRadioButtons

59 planoJRadioButton.addItemListener(

60 new ManejadorRadioButton( fuentePlana ) );

61 negritaJRadioButton.addItemListener(

62 new ManejadorRadioButton( fuenteNegrita ) );

63 italicaJRadioButton.addItemListener(

64 new ManejadorRadioButton( fuenteItalica ) );

65 negritaItalicaJRadioButton.addItemListener(

66 new ManejadorRadioButton( fuenteNegritaItalica ) );

67 } // fin del constructor VentanaRadioButton

68

69 // clase privada interna para manejar los eventos de los botones de radio

70 private class ManejadorRadioButton implements ItemListener {

71

72 private Font fuente; // fuente asociada con su receptor

73

74 public ManejadorRadioButton( Font f ) {

75

76 fuente = f; // poner la fuente de este receptor

77 } // fin del constructor ManejadorRadioButton

78

79 // manejador de eventos botones de radio

80 public void itemStateChanged( ItemEvent event ) {

81

82 campoTexto.setFont( fuente ); // poner fuente de campoTexto

83 } // fin del metodo itemStateChanged

84 } // fin de la clase privada ManejadorRadioButton

85 } // fin de la clase VentanaRadioButton

Las lıneas 35–42 en el constructor crean cuatro objetos JRadioButton yson agregados al JFrame. Cada JRadioButton es creado con una llamada a unconstructor como el que esta en la lınea 35. Este constructor indica la etiquetaque aparecera a la derecha del JRadioButton por defecto y el estado inicial.Un segundo argumento true indica que el JRadioButton debera aparecer

Page 63: notasGUI

3.8 Botones que mantienen estado 63

seleccionado cuando este sea mostrado.La lınea 45 instancia un objeto grupoRadio de tipo ButtonGroup. Este

objeto es el aglutinador que forma la relacion logica entre los cuatro objetosJRadioButton y permite que solamente uno de los cuatro sea selecciona-do a la vez. Es posible que no este seleccionado algun JRadioButton en unButtonGroup, y ocurre cuando no hay ningun JRadioButton preselecciona-do y el usuario tampoco ha seleccionado todavıa ningun JRadioButton. Laslıneas 46–49 usan el metodo add de ButtonGroup para asociar cada uno delos JRadioButton con grupoRadio. Si mas de un objeto JRadioButton selec-cionado es agregado al grupo, el primer objeto seleccionado que fue agregadosera seleccionado cuando la GUI sea mostrada.

JRadioButtons, parecidos a los JCheckBoxes, generan eventos ItemEventscuando son pulsados. Las lıneas 59–66 crean cuatro instancias de la clase in-terna ManejadorRadioButton, declarada en las lıneas 70–84. En el ejemplo,cada objeto receptor de eventos esta registrado para manejar los ItemEventgenerados cuando el usuario pulsa un JRadioButton particular. Observar quecada objeto ManejadorRadioButton esta inicializado con un objeto fuenteparticular creado en las lıneas 52–55.

La clase ManejadorRadioButton, lıneas 70–84, implementa la interfazItemListener por lo que esta clase puede manejar los eventos ItemEvents

generados por los JRadioButtons. El constructor guarda el objeto Font

que este recibe como un argumento en la variable de instancia del obje-to receptor de eventos fuente, declarado en la lınea 72. Cuando el usua-rio pulsa un JRadioButton, grupoRadio apaga el JRadioButton seleccio-nado previamente y el metodo itemStateChanged, lineas 80–83, pone lafuente en el JTextField a la fuente guardada correspondiente al objetoreceptor de eventos del JRadioButton. En la lınea 82 de la clase internaManejadorRadioButton usa la variable de instancia campoTexto de la clasede nivel superior para poner la fuente.

La clase PruebaRadioButton, que se muestra enseguida, contiene el meto-do main que ejecuta la aplicacion VentanaRadioButton

1 // PruebaRadioButton.java

2 // Prueba VentanaRadioButton.

3 import javax.swing.JFrame;

4

5 public class PruebaRadioButton {

6

7 public static void main( String args[] ) {

Page 64: notasGUI

64 Componentes GUI

8

9 VentanaRadioButton ventanaRadioButton = new VentanaRadioButton();

10 ventanaRadioButton.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaRadioButton.setSize( 350, 100 ); // poner tama~no ventana

12 ventanaRadioButton.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase PruebaRadioButton

3.9. JComboBox

Una caja combinada, llamada a veces lista despegable, da una lista deobjetos de la cual el usuario puede hacer una sola seleccion. Las cajas com-binadas estan implementadas con la clase JComboBox, la cual extiende aJComponent. Un JComboBox genera eventos ItemEvents como un JCheckBox

o un JRadioButton.La siguiente aplicacion usa un JComboBox para dar una lista de cuatro

nombres de archivos de los cuales el usuario puede seleccionar la imagen amostrar. Cuando el usuario selecciona un nombre, la aplicacion muestra laimagen correspondiente como un Icon en un JLabel.

1 // VentanaComboBox.java

2 // Usando un JComboBox para seleccionar una imagen a mostrar

3 import java.awt.FlowLayout;

4 import java.awt.event.ItemListener;

5 import java.awt.event.ItemEvent;

6 import javax.swing.JFrame;

7 import javax.swing.JLabel;

8 import javax.swing.JComboBox;

9 import javax.swing.Icon;

10 import javax.swing.ImageIcon;

11

12 public class VentanaComboBox extends JFrame {

13

14 private JComboBox imagenesJComboBox; // para tener los nombres de los ico nos

15 private JLabel etiqueta; // etiqueta para mostrar icon seleccionado

16

17 private String nombres[] = {"alacarte.png","distributor-logo.png",

18 "gnome-gnibbles.png","gnome-robots.png"};

19 private Icon iconos[] = {

20 new ImageIcon( getClass().getResource( nombres[ 0 ] ) ),

21 new ImageIcon( getClass().getResource( nombres[ 1 ] ) ),

22 new ImageIcon( getClass().getResource( nombres[ 2 ] ) ),

Page 65: notasGUI

3.9 JComboBox 65

23 new ImageIcon( getClass().getResource( nombres[ 3 ] ) ) };

24

25 // constructor VentanaComboBox agrega JComboBox a JFrame

26 public VentanaComboBox() {

27

28 super( "Probando JComboBox" );

29 setLayout( new FlowLayout() ); // fijar dise~no de ventana

30

31 imagenesJComboBox = new JComboBox( nombres ); // configurar JComboBox

32 imagenesJComboBox.setMaximumRowCount( 3 ); // mostrar tres renglones

33

34 imagenesJComboBox.addItemListener(

35 new ItemListener() { // clase interna anonima

36

37 // manejo de evento JComboBox

38 public void itemStateChanged( ItemEvent event ) {

39

40 // determinar si evento es seleccionado

41 if ( event.getStateChange() == ItemEvent.SELECTED )

42 etiqueta.setIcon( iconos[

43 imagenesJComboBox.getSelectedIndex() ] );

44 } // fin del metodo itemStateChanged

45 } // fin de la clase interna anonima

46 ); // fin de la llamada a addItemListener

47

48 add( imagenesJComboBox ); // agregar combobox a JFrame

49 etiqueta = new JLabel( iconos[ 0 ] ); // mostrar el primer icono

50 add( etiqueta ); // agregar etiqueta a JFrame

51 } // fin del constructor VentanaComboBox

Usando una clase interna anonima para manejo de eventos. Laslıneas 34–46 son una sentencia que declara la clase receptora de eventos, creaun objeto de esa clase y registra ese objeto como el receptor para los eventosItemEvents de imagenesJComboBox. En este ejemplo, el objeto receptor deevento es una instancia de una clase interna anonima—una forma especialde clase interna que esta declarada sin un nombre y que tıpicamente aparecedentro de la declaracion de un metodo. Al igual que con otras clases internas,una clase interna anonima puede acceder los miembros de la clase de nivelsuperior. Sin embargo, una clase interna anonima tiene acceso limitado a lasvariables locales del metodo en donde esta declarada. Como sea una claseanonima, un objeto de esta clase debera ser creado en el punto donde laclase esta declarada, iniciando en la lınea 35.

Page 66: notasGUI

66 Componentes GUI

Las lıneas 34–46 son una llamada al metodo addItemListener de image-nesJComboBox. El argumento a este metodo debera ser un objeto que seaun ItemListener, es decir, cualquier objeto de una clase que implementeItemListener. Las lıneas 35–45 son una expresion clase-creacion instan-cia que declara una clase interna anonima y crea un objeto de esa cla-se. Una referencia a ese objeto es entonces pasada como el argumento aaddItemListener. La sintaxis ItemListener() despues de new inicia la de-claracion de una clase interna anonima que implementa la interfaz ItemListe-ner. Los parentesis despues de ItemListener indican una llamada al cons-tructor por defecto de la clase interna anonima.

La clase PruebaComboBox, que se muestra enseguida, contiene el metodomain que ejecuta la aplicacion VentanaComboBox descrita previamente.

1 // PruebaComboBox.java

2 // Probando VentanaComboBox.

3 import javax.swing.JFrame;

4

5 public class PruebaComboBox {

6

7 public static void main( String args[] ) {

8

9 VentanaComboBox ventanaComboBox = new VentanaComboBox();

10 ventanaComboBox.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaComboBox.setSize( 350, 150 ); // fijar tama~no de ventana

12 ventanaComboBox.setVisible( true ); // mostrar frame

13 } // fin de main

14 } // fin de la clase

3.10. JList

Una lista muestra una serie de artıculos de los cuales el usuario podrıaseleccionar uno o mas de ellos. Las listas son creadas con la clase JList,la cual directamente extiende la clase JComponent. La clase JList soportalistas de seleccion simple, lo que permite que solamente un artıculo seaseleccionado a la vez y listas de seleccion multiple, las cuales permitenseleccionar cualquier numero de elementos.

La siguiente aplicacion crea una JList conteniendo 13 nombres de colores.Cuando un nombre de color es pulsado en la JList, un evento ListSelection-Event ocurre y la aplicacion cambia el color de fondo de la aplicacion al colorseleccionado.

Page 67: notasGUI

3.10 JList 67

1 // VentanaLista.java

2 // Seleccionando colores de un JList.

3 import java.awt.FlowLayout;

4 import java.awt.Color;

5 import javax.swing.JFrame;

6 import javax.swing.JList;

7 import javax.swing.JScrollPane;

8 import javax.swing.event.ListSelectionListener;

9 import javax.swing.event.ListSelectionEvent;

10 import javax.swing.ListSelectionModel;

11

12 public class VentanaLista extends JFrame {

13

14 private JList colorJList; // lista para mostrar colores

15 private final String nombreColores[] = { "Negro", "Azul", "Cian",

16 "Gris obscuro", "Gris", "Verde", "Gris claro", "Magenta",

17 "Naranja", "Rosa", "Rojo", "Blanco", "Amarillo" };

18 private final Color colores[] = { Color.BLACK, Color.BLUE, Color.CYAN,

19 Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.LIGHT_GRAY,

20 Color.MAGENTA, Color.ORANGE, Color.PINK, Color.RED, Color.WHITE,

21 Color.YELLOW };

22

23 // constructor VentanaLista agrega JScrollPane conteniendo JList a JFrame

24 public VentanaLista() {

25

26 super( "Prueba Lista" );

27 setLayout( new FlowLayout() ); // fijar dise~no ventana

28

29 colorJList = new JList( nombreColores ); // crear con nombreColores

30 colorJList.setVisibleRowCount( 5 ); // mostrar cinco renglones a la vez

31

32 // no permitir seleccion multiple

33 colorJList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );

34

35 // agregar un JScrollPane conteniendo JList al frame

36 add( new JScrollPane( colorJList ) );

37

38 colorJList.addListSelectionListener(

39 new ListSelectionListener() { // clase anonima interna

40

41 // maneja eventos de seleccion de lista

42 public void valueChanged( ListSelectionEvent event ) {

43

44 getContentPane().setBackground(

45 colores[ colorJList.getSelectedIndex() ] );

Page 68: notasGUI

68 Componentes GUI

46 } // fin del metodo valueChanged

47 } // fin de la clase anonima interna

48 ); // fin de la llamada addListSelectionListener

49 } // fin del constructor VentanaLista

50 } // fin de la clase VentanaLista

Diferente a un JComboBox, una JList no proporciona una barra de des-plazamiento si hay mas artıculos en la lista que el numero de renglones vi-sibles. En este caso, un objeto JScrollPane es usado para dar la capacidadde desplazar. La lınea 36 agrega una nueva instancia de clase JScrollPane alJFrame. El constructor JScrollPane recibe como su argumento el JComponentque necesita la funcion de desplazamiento, en este caso, colorJList. Por de-fecto, la barra de desplazamiento aparece solamente cuando el numero deartıculos en el JList excede el numero de artıculos visibles.

La clase PruebaLista contiene el metodo main que ejecuta la aplicacionVentanaLista.

1 // PruebaLista.java

2 // Seleccionando colores desde un JList.

3

4 import javax.swing.JFrame;

5 public class PruebaLista {

6

7 public static void main( String args[] ) {

8

9 VentanaLista ventanaLista = new VentanaLista(); // crear VentanaLista

10 ventanaLista.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaLista.setSize( 350, 150 ); // fijar tama~no ventana

12 ventanaLista.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase PruebaLista

3.11. Listas de seleccion multiple

Una lista de seleccion multiple permite al usuario seleccionar variosartıculos de un JList. Una lista SINGLE INTERVAL SELECTION permite se-leccionar un rango continuo de artıculos. Para hacerlo, pulsar en el primerelemento, entonces mantener presionada la tecla cambio mientras se presionaen el ultimo elemento en el rango. Una lista MULTIPLE INTERVAL SELECTION

permite seleccion de rangos continuos como se describio para una lista SINGLE

Page 69: notasGUI

3.11 Listas de seleccion multiple 69

INTERVAL SELECTION. Tales listas permiten articulos variados para ser selec-cionados manteniendo presionada la tecla Ctrl mientras se pulsa sobre cadaartıculo a seleccionar. Para deseleccionar un artıculo, manteniendo presiona-da la tecla Ctrl mientras se pulsa el artıculo una segunda vez.

La siguiente aplicacion usa listas de seleccion multiple para copiar artıcu-los de una JList a otra. Una lista es una lista MULTIPLE INTERVAL SELECTION

y la otra es una lista SINGLE INTERVAL SELECTION.

1 // VentanaSeleccionMultiple.java

2 // Copiar artıculos de una lista a otra.

3 import java.awt.FlowLayout;

4 import java.awt.event.ActionListener;

5 import java.awt.event.ActionEvent;

6 import javax.swing.JFrame;

7 import javax.swing.JList;

8 import javax.swing.JButton;

9 import javax.swing.JScrollPane;

10 import javax.swing.ListSelectionModel;

11

12 public class VentanaSeleccionMultiple extends JFrame {

13

14 private JList colorJList; // lista para mantener los nombres de los colores

15 private JList copiaJList; // lista para copiar nombres de colores

16 private JButton copiarJButton; // boton para copiar nombres seleccionados

17 private final String nombreColores[] = { "Negro", "Azul", "Cian",

18 "Gris obscuro", "Gris", "Verde", "Gris claro", "Magenta",

19 "Naranja", "Rosa", "Rojo", "Blanco", "Amarillo" };

20

21 // constructor VentanaSeleccionMultiple

22 public VentanaSeleccionMultiple() {

23

24 super( "Listas de Seleccion Multiple" );

25 setLayout( new FlowLayout() ); // fijar dise~no ventana

26

27 colorJList = new JList( nombreColores ); // nombres de todos los colores

28 colorJList.setVisibleRowCount( 5 ); // mostrar cinco renglones

29 colorJList.setSelectionMode(

30 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );

31 add( new JScrollPane( colorJList ) ); // agregar lista con scrollpane

32

33 copiarJButton = new JButton( "Copiar >>>" ); // crear boton copiar

34 copiarJButton.addActionListener(

35

36 new ActionListener() { // clase anonima interna

Page 70: notasGUI

70 Componentes GUI

37

38 // manejar boton evento

39 public void actionPerformed( ActionEvent event ) {

40

41 // colocar valores seleccionados en copiaJList

42 copiaJList.setListData( colorJList.getSelectedValues() );

43 } // fin metodo actionPerformed

44 } // fin de la clase interna anonima

45 ); // fin de la llamada a addActionListener

46

47 add( copiarJButton ); // agregar boton copiar al JFrame

48

49 copiaJList = new JList(); // crear lista con los nombres copiados

50 copiaJList.setVisibleRowCount( 5 ); // mostrar 5 renglones

51 copiaJList.setFixedCellWidth( 100 ); // fijar ancho

52 copiaJList.setFixedCellHeight( 15 ); // fijar alto

53 copiaJList.setSelectionMode(

54 ListSelectionModel.SINGLE_INTERVAL_SELECTION );

55 add( new JScrollPane( copiaJList ) ); // agregar lista con scrollpane

56 } // fin del constructor VentanaSeleccionMultiple

57 } // fin de la clase VentanaSeleccionMultiple

En el codigo anterior, la lınea 27 crea colorJList del tipo JList y loinicializa con las cadenas en el arreglo nombreColores. La lınea 28 pone elnumero de renglones visibles en colorJList a 5. Las lıneas 29–30 indicanque colorJList es una lista de seleccion de intervalo multiple. La lınea 31agrega un JScrollPane nuevo conteniendo a colorJList a la ventana. Laslıneas 49–55 realizan tareas similares para copiaJList, la cual es declara-da como lista de seleccion de intervalo unica. La lınea 51 usa el metodosetFixedCellWidth de JLista para poner el ancho de copiaJList a 100pıxeles. La lınea 52 usa el metodo setFixedCellHeight de JList para po-ner el alto de cada artıculo en la JList a 15 pıxeles.

No hay eventos para indicar que el usuario ha hecho selecciones multiplesen una lista de seleccion multiple. Normalmente, un evento generado porotro componente GUI, conocido como un evento externo indica cuando lasselecciones multiples en una JList debera ser procesada. En el ejemplo, elusuario pulsa el JButton llamado copiarJButton para lanzar el evento quecopia los artıculos seleccionados en colorJList a copiaJList.

Las lıneas 39–45 declaran, crean y registran un ActionListener para elcopiarJButton. Cuando el usuario pulsa el boton, el metodo actionPerfor-med, lıneas 39–43, usa el metodo setListData para poner los artıculos mos-trados en copiaJList. La lınea 42 llama al metodo getSelectedValues de

Page 71: notasGUI

3.12 Manejo de eventos del raton 71

colorJList, el cual regresa un arreglo de Objects representando los artıculosseleccionados en colorJList. En el ejemplo, el arreglo regresado es pasadocomo argumento al metodo setListData de copiaJList.

1 // PruebaSeleccionMultiple.java

2 // Probando VentanaSeleccionMultiple.

3 import javax.swing.JFrame;

4

5 public class PruebaSeleccionMultiple {

6

7 public static void main( String args[] ) {

8

9 VentanaSeleccionMultiple ventanaSeleccionMultiple =

10 new VentanaSeleccionMultiple();

11 ventanaSeleccionMultiple.setDefaultCloseOperation(

12 JFrame.EXIT_ON_CLOSE );

13 ventanaSeleccionMultiple.setSize( 350, 140 ); // poner tama~no ventana

14 ventanaSeleccionMultiple.setVisible( true ); // mostrar ventana

15 } // fin main

16 } // fin de la clase PruebaSeleccionMultiple

3.12. Manejo de eventos del raton

Se presenta las interfaces MouseListener y MouseMotionListener paramanejo de eventos del raton. Los eventos del raton pueden ser atrapa-dos por cualquier componente GUI que derive de java.awt.Component. Losmetodos de las interfaz MouseListener se resumen a continuacion.

public void mousePressed( MouseEvent event ) Llamado cuando un bo-ton del raton es presionado mientras el apuntador del raton esta sobreun componente.

public void mouseClicked( MouseEvent event ) Llamado cuando un bo-ton del raton es presionado y soltado mientras el apuntador del ratonpermanece estacionario sobre un componente. Este evento es siempreprecedido por una llamada a mousePressed.

public void mouseReleased( MouseEvent event ) Llamado cuando unboton del raton es soltado despues de haber sido presionado. Este even-to es siempre precedido por una llamada a mousePressed y uno o masllamadas a mouseDragged.

Page 72: notasGUI

72 Componentes GUI

public void mouseEntered( MouseEvent event ) Llamado cuando el apun-tador del raton entra en la region de un componente.

public void mouseExited( MouseEvent event ) Llamado cuando el apun-tador del raton deja la region de un componente.

Los metodos de MouseMotionListener se resumen a continuacion.

public void mouseDragged( MouseEvent event ) Llamado cuando el bo-ton del raton es presionado mientra el apuntador del raton esta sobreun componente y el raton es movido mientras el boton del raton semantiene presionado. Este evento es siempre precedido por una llama-do a mousePressed. Todos los eventos de arrastre son mandados alcomponente en el cual el usuario empezo a arrastrar el raton.

public void mouseMoved( MouseEvent event ) Llamado cuando el ratones movido cuando el apuntador del cursor esta sobre un componente.Todos los eventos movimiento son mandados al componente sobre elcual el raton esta posicionado actualmente.

El paquete javax.swing.event contiene la interfaz MouseInputListener,la cual extiende las interfaces MouseListener y MouseMotionListener paracrear una sola interfaz conteniendo todos los metodos de estas interfaces. Losmetodos de MouseListener y MouseMotionListener son llamados cuandoel raton interactua con un componente si los objetos receptores de eventosapropiados estan registrados para ese componente.

Cada uno de los metodos manejadores de eventos del raton toman un ob-jeto MouseEvent como su argumento. Un objeto MouseEvent contiene infor-macion acerca del evento de raton que ocurrio, incluyendo las coordenadas xe y del lugar donde el evento ocurrio. Estas coordenadas estan medidas desdela esquina superior izquierda del componente GUI en el cual el evento ocu-rrio. La coordenada x inicia en 0 y se incrementa de izquierda a derecha. Lacoordenada y inicia en 0 y se incrementa de arriba hacia abajo. Ademas, losmetodos y constantes de la clase InputEvent, la superclase de MouseEvent,permiten a una aplicacion determinar cual boton del raton fue presionado.

Java tambien proporciona la interfaz MouseWheelListener para permi-tir a las aplicaciones responder a la rotacion de la rueda del raton. Es-ta interfaz declara el metodo mouseWheelMoved, la cual recibe un evento

Page 73: notasGUI

3.12 Manejo de eventos del raton 73

MouseWheelEvent como su argumento. La clase MouseWheelEvent, una sub-clase de MouseEvent, contiene metodos que permiten al manejador de eventosobtener informacion acerca de la cantidad de rotacion de la rueda.

Siguiendo eventos del raton en un JPanel. La aplicacion HuellaRaton,que se muestra a continuacion, prueba los metodos de las interfaces MouseLis-tener y MouseMotionListener. La aplicacion implementa ambas interfacespor lo que puede escuchar sus propios eventos de raton. Observar que todoslos metodos de estas dos interfaces deben ser declarados por el programadorcuando una clase implementa ambas interfaces. Cada evento de raton en esteejemplo muestra una cadena en la JLabel llamada barraEstado en la parteinferior de la ventana.

1 // VentanaHuellaRaton.java

2 // Mostrando eventos del raton.

3 import java.awt.Color;

4 import java.awt.BorderLayout;

5 import java.awt.event.MouseListener;

6 import java.awt.event.MouseMotionListener;

7 import java.awt.event.MouseEvent;

8 import javax.swing.JFrame;

9 import javax.swing.JLabel;

10 import javax.swing.JPanel;

11

12 public class VentanaHuellaRaton extends JFrame {

13

14 private JPanel panelRaton; // panel en el cual los eventos del raton ocur ren

15 private JLabel barraEstado; // etiqueta que muestra informacion del event o

16

17 // constructor VentanaHuellaRaton configura la GUI y

18 // registra manejadores de evento de raton

19 public VentanaHuellaRaton() {

20

21 super( "Mostrando Eventos de Raton" );

22

23 panelRaton = new JPanel(); // crear panel

24 panelRaton.setBackground( Color.WHITE ); // poner color de fondo

25 add( panelRaton, BorderLayout.CENTER ); // agregar panel al JFrame

26

27 barraEstado = new JLabel( "Raton fuera de JPanel" );

28 add( barraEstado, BorderLayout.SOUTH ); // agregar etiqueta al JFrame

29

30 // crear y registrar receptores para eventos de raton y movimiento

Page 74: notasGUI

74 Componentes GUI

31 ManejadorRaton manejador = new ManejadorRaton();

32 panelRaton.addMouseListener( manejador );

33 panelRaton.addMouseMotionListener( manejador );

34 } // fin del constructo VentanaHuellaRaton

35

36 private class ManejadorRaton implements MouseListener,

37 MouseMotionListener {

38

39 // manejadores de eventos MouseListener

40 // manejar evento cuando el boton del raton fue presionado y soltado

41 public void mouseClicked( MouseEvent event ) {

42

43 barraEstado.setText( String.format( "Pulsado en [%d, %d]",

44 event.getX(), event.getY() ) );

44 event.getX(), event.getY() ) );

45 } // fin del metodo mouseClicked

46

47 // manejar evento cuando el boton del raton fue presionado

48 public void mousePressed( MouseEvent event ) {

49

50 barraEstado.setText( String.format( "Pressionado en [%d, %d]",

51 event.getX(), event.getY() ) );

52 } // fin del metodo mousePressed

53

54 // manejar evento cuando el boton del raton fue soltado despues de arr astrar

55 public void mouseReleased( MouseEvent event ) {

56

57 barraEstado.setText( String.format( "Soltado en [%d, %d]",

58 event.getX(), event.getY() ) );

59 } // fin del metodo mouseReleased

60

61 // manejar evento cuando el raton ingresa al area

62 public void mouseEntered( MouseEvent event ) {

63

64 barraEstado.setText( String.format( "Raton entrado en [%d, %d]",

65 event.getX(), event.getY() ) );

66 panelRaton.setBackground( Color.GREEN );

67 } // fin del metodo mouseEntered

68

69 // manejar evento cuando raton salga del area

70 public void mouseExited( MouseEvent event ) {

71

72 barraEstado.setText( "Raton fuera del JPanel" );

73 panelRaton.setBackground( Color.WHITE );

74 } // fin del metodo mouseExited

Page 75: notasGUI

3.13 Clases adaptadoras 75

75

76 // manejador de eventos MouseMotionListener

77 // manejar evento cuando el usuario arrastra con boton presionado

78 public void mouseDragged( MouseEvent event ) {

79

80 barraEstado.setText( String.format( "Arrastrado en [%d, %d]",

81 event.getX(), event.getY() ) );

82 } // fin del metodo mouseDragged

83

84 // manejar evento cuando el usuario mueve el raton

85 public void mouseMoved( MouseEvent event ) {

86 barraEstado.setText( String.format( "Movido en [%d, %d]",

87 event.getX(), event.getY() ) );

88 } // fin del metodo mouseMoved

89 } // fin de la clase interna ManejadorRaton

90 } // fin de la clase VentanaHuellaRaton

La clase HuellaRaton se usa para crear un objeto del tipo VentanaHuellaRaton.

1 // HuellaRaton.java

2 // Probrando VentanaHuellaRaton.

3 import javax.swing.JFrame;

4

5 public class HuellaRaton {

6

7 public static void main( String args[] ) {

8

9 VentanaHuellaRaton VentanaHuellaRaton = new VentanaHuellaRaton();

10 VentanaHuellaRaton.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 VentanaHuellaRaton.setSize( 350, 200 ); // fijar tama~no ventana

12 VentanaHuellaRaton.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase HuellaRaton

3.13. Clases adaptadoras

Varias interfaces receptoras de eventos, como MouseListener y Mouse-MotionListener, tienen metodos multiples. No siempre es deseable declararcada metodo en una interfaz receptora de eventos. Por ejemplo, una aplica-cion podrıa solamente necesitar el manejador mouseClicked de MouseListenero el manejador mouseDragged de MouseMotionListener. La interfaz Window-Listener especifica siete metodos manejados de eventos. Para varias de las

Page 76: notasGUI

76 Componentes GUI

interfaces receptoras que tienen metodos multiples, los paquetes java.awt.-event y javax.swing.event dan clases adaptadoras receptoras de eventos.Una clase adaptadora implementa una interfaz y da una implementacionpor defecto, con un cuerpo de metodo vacıo, de cada metodo de la interfaz. Semuestra a continuacion varias clases adaptadoras de java.awt.event y lasinterfaces que estas implementan. Se puede extender una clase adaptadorapara heredar la implementacion por defecto de cada metodo y subsecuen-temente sobreescribir solamente los metodos que se necesiten para manejareventos.

Clase adaptadora Interfaz implementadaComponentAdapter ComponentListener

ContainerAdapter ContainerListener

FocusAdapter FocusListener

KeyAdapter KeyListener

MouseAdapter MouseListener

MouseMotionAdapter MouseMotionListener

WindowAdapter WindowListener

Extendiendo MouseAdapter. La siguiente aplicacion muestra como deter-minar el numero de pulsaciones y como distinguir entre los diferentes botonesdel raton. El receptor de eventos en la aplicacion es un objeto de la cla-se interna ManejadorPulsacionesRaton, en las lıneas 26–46 que extiende aMouseAdapter, con lo que solo se requiere declarar el metodo mouseClicked

que se necesita en el ejemplo.

1 // VentanaDetallesRaton.java

2 // Mostrando pulsaciones del raton y distinguiendo entre sus botones

3 import java.awt.BorderLayout;

4 import java.awt.Graphics;

5 import java.awt.event.MouseAdapter;

6 import java.awt.event.MouseEvent;

7 import javax.swing.JFrame;

8 import javax.swing.JLabel;

9

10 public class VentanaDetallesRaton extends JFrame {

11

12 private String detalles; // cadena representante

13 private JLabel barraEstado; // JLabel aparece en la parte inferior de la ventana

14

15 // constructor configura cadena de barra de tıtulos y registra receptor

Page 77: notasGUI

3.13 Clases adaptadoras 77

16 public VentanaDetallesRaton() {

17

18 super( "Pulsaciones raton y botones" );

19

20 barraEstado = new JLabel( "Pulsar el raton" );

21 add( barraEstado, BorderLayout.SOUTH );

22 addMouseListener( new ManejadorPulsacionesRaton() ); // agregar maneja dor

23 } // fin del constructor VentanaDetallesRaton

24

25 // clase interna para manejar eventos del raton

26 private class ManejadorPulsacionesRaton extends MouseAdapter {

27

28 // manejar evento pulsacion y determinar cual boton se presiono

29 public void mouseClicked( MouseEvent event ) {

30

31 int posX = event.getX(); // obtener la posicion x del raton

32 int posY = event.getY(); // obtener la posicion y del raton

33

34 detalles = String.format( "Pulsado %d ve%s",

35 event.getClickCount(), event.getClickCount()==1?"z":"ces");

36

37 if ( event.isMetaDown() ) // boton derecho del raton

38 detalles += " con boton derecho del raton";

39 else if ( event.isAltDown() ) // boton central del raton

40 detalles += " con boton central del raton";

41 else // boton izquierdo del raton

42 detalles += " con boton izquierdo del raton";

43

44 barraEstado.setText( detalles ); // mostrar mensaje en barraEstado

45 } // fin del metodo mouseClicked

46 } // fin de la clase privada interna ManejadorPulsacionesRaton

47 } // fin de la clase VentanaDetallesRaton

Un usuario de una aplicacion de Java podrıa estar en un sistema conun raton de uno, dos o tres botones. Java proporciona un mecanismo paradistinguir entre los botones del raton. La clase MouseEvent hereda variosmetodos de la clase InputEvent que pueden distinguir los botones del ratonen un raton multiboton o un raton que pueda simular uno multiboton con unacombinacion de tecla y de pulsacion del raton. La siguiente tabla muestra losmetodos InputEvent usados para distinguir entre las pulsaciones del raton.Java asume que cada raton contiene un boton izquierdo. En el caso de unraton de uno o dos botones, la aplicacion de Java supone que el boton centraldel raton es pulsado si el usuario mantiene presionada la tecla Alt y pulsa el

Page 78: notasGUI

78 Componentes GUI

boton izquierdo en un raton de dos botones o el unico boton en un raton conun solo boton. En el caso de un raton de un boton, una aplicacion de Javasupone que el boton derecho es pulsado si el usuario mantiene presionada latecla Meta y pulsa el boton del raton.

Metodo DescripcionisMetaDown() Regresa true cuando el usuario pulsa el

boton derecho en un raton con dos o tresbotones. Para simular la pulsacion con elboton derecho en un raton de un boton,el usuario debera mantener presionada latecla Meta y pulsar el boton del raton.

isAltDown() Regresa true cuando el usuario pulsa elboton central en un raton con tres tresbotones. Para simular la pulsacion con elboton central en un raton con uno o dosbotones, el usuario puede presionar la te-cla Alt del teclado y pulsar el unico botono el boton izquierdo, respectivamente.

1 // DetallesRaton.java

2 // Probando VentanaDetallesRaton.

3 import javax.swing.JFrame;

4

5 public class DetallesRaton {

6

7 public static void main( String args[] ) {

8

9 VentanaDetallesRaton ventanaDetallesRaton = new VentanaDetallesRaton() ;

10 ventanaDetallesRaton.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaDetallesRaton.setSize( 400, 150 ); // fijar tama~no ventana

12 lventanaDetallesRaton.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase DetallesRaton

3.14. Subclase JPanel para dibujar con el raton

En la seccion 3.12 se muestra como seguir los eventos del raton en unJPanel. En esta seccion, se usa un JPanel como una area dedicada dedibujo en la cual el usuario puede dibujar arrastrando el raton. Ademas,

Page 79: notasGUI

3.14 Subclase JPanel para dibujar con el raton 79

en esta seccion se muestra un receptor de eventos que extiende una claseadaptadora.

El metodo paintComponent Los componentes ligeros de Swing que extien-den la clase JComponent, como JPanel, contienen al metodo paintComponent,el cual es llamado cuando un componente es mostrado. Sobreescribiendo estemetodo, se puede indicar como dibujar figuras usando las capacidades graficasde Java. Cuando se configura un JPanel para usarlo como una area dedicadade dibujo, la subclase debera sobreescribir el metodo paintComponent y lla-mar la version de la superclase de paintComponent como la primera sentenciaen el cuerpo del metodo para asegurar que el componente se muestra correc-tamente. La razon para esto es que la subclases de JComponent soportantransparencia. Para mostrar un componente correctamente, el programadebe determinar si el componente es transparente. El codigo que lo determi-na esta en la implementacion paintComponent de la superclase JComponent.Cuando un componente es transparente, paintComponent no limpiara sufondo cuando el programa muestre el componente. Cuando un componentees opaco, paintComponent limpia el fondo del componente antes de que elcomponente sea mostrado. Si la version de la superclase de paintComponent

no es llamado, un componente opaco GUI no sera mostrado correctamenteen la interfaz del usuario. Tambien, si la version de la superclase es llamadadespues de hacer las sentencias de dibujado configuradas, los resultados tıpi-camente seran borrados. La transparencia de un componente ligero de Swingpuede ser puesta con el metodo setOpaque, un argumento false indica queel componente es transparente.

Definiendo la configuracion del area de dibujado La aplicacion Pintar,que se esta enseguida, muestra una subclase configurada de JPanel que esusada para crear una area dedicada de dibujo. La aplicacion usa el manejo deevento mouseDragged para crear una aplicacion simple de dibujo. El usuariopuede dibujar arrastrando el raton sobre el JPanel. El ejemplo no usa elmetodo mouseMoved, por lo que la clase receptora de eventos, la clase inter-na anonima en las lıneas 22–34, extiende MouseMotionAdapter. Como estaclase ya declara a mouseMoved y mouseDragged, simplemente se sobreescribemouseDragged para dar el manejo de evento que requiere la aplicacion.

1 // PintaPanel.java

2 // Usando la clase MouseMotionAdapter.

Page 80: notasGUI

80 Componentes GUI

3 import java.awt.Point;

4 import java.awt.Graphics;

5 import java.awt.event.MouseEvent;

6 import java.awt.event.MouseMotionAdapter;

7 import javax.swing.JPanel;

8

9 public class PintaPanel extends JPanel {

10

11 private int cuentaPuntos = 0; // contar numero de puntos

12

13 // arreglo de 10000 referencias java.awt.Point

14 private Point puntos[] = new Point[ 10000 ];

15

16 // configurar la GUI y registrar el manejador de eventos del raton

17 public PintaPanel() {

18

19 // manejar el evento del moviemiento del raton en la ventana

20 addMouseMotionListener(

21

22 new MouseMotionAdapter() { // clase anonima interna

23

24 // guardar las coordenadas del arrastre y repintar

25 public void mouseDragged( MouseEvent event ) {

26

27 if ( cuentaPuntos < puntos.length ) {

28

29 puntos[ cuentaPuntos ] = event.getPoint(); // asignar punto

30 cuentaPuntos++; // incrementar el contador

31 repaint(); // repintar JFrame

32 } // fin if

33 } // fin metodo mouseDragged

34 } // fin de la clase interna anonima

35 ); // fin de la llamada a addMouseMotionListener

36 } // fin del constructor PintaPanel

37

38 // dibujar elipses en caja contenedora de 4x4 en la posicion dada en la ventana

39 public void paintComponent( Graphics g ) {

40

41 super.paintComponent( g ); // limpiar el area de dibujado

42

43 // dibujar todos los puntos del arreglo

44 for ( int i = 0; i < cuentaPuntos; i++ )

45 g.fillOval( puntos[ i ].x, puntos[ i ].y, 4, 4 );

46 } // fin del metodo paintComponent

47 } // fin de la clase PintaPanel

Page 81: notasGUI

3.14 Subclase JPanel para dibujar con el raton 81

La clase PintaPanel, que se muestra a continuacion, extiende a JPanel

para crear el area dedicada de dibujo. Las lıneas 3–7 importan las clasesusadas en la clase PaintPanel. La clase Point del paquete java.awt re-presenta un coordenada x − y. Se usan objetos de esta clase para guardarlas coordenadas de cada evento arrastrar. La clase Graphics es usada paradibujar.

En este ejemplo, se usa un arreglo de 10,000 puntos, lınea 14, para guar-dar la localidad en la cual el evento de arrastrar el raton ocurre. Como severa, el metodo paintComponent usa estos puntos para dibujar. La variablede instancia cuentaPuntos, lınea 11, mantiene el numero total de puntoscapturados de los eventos de arrastre hasta el momento.

Las lıneas 20–35 registra un evento MouseMotionListener para escu-char los eventos de movimiento del raton de PintarPanel. Las lıneas 22–34crean un objeto de una clase interna anonima que extiende la clase adap-tadora MouseMotionAdapter. Se recuerda que MouseMotionAdapter imple-menta MouseMotionListener, por lo que el objeto de la clase interna es unMouseMotionListener. La clase interna anonima hereda una implementa-cion por defecto de los metodos mouseMoved y mouseDragged, por lo que yasatisface los requerimientos de que todos los metodos de la interfaz deban serimplementados. Sin embargo, los metodos por defecto no hacen nada cuan-do son llamados. Por lo tanto, se sobreescribe el metodo mouseDragged enlas lıneas 25–33 para capturar las coordenadas de un evento de arrastre yse guardan como un objeto Point. La lınea 27 asegura que se guarden lascoordenadas del evento solamente si todavıa hay espacio en el arreglo. Sihay, en la lınea 29 se llama al metodo getPoint de MouseEvent para obte-ner el punto donde el evento ocurrio y guardarlo en el arreglo en el ındicecuentaPuntos. La lınea 30 incrementa cuentaPuntos, y la lınea 31 llama almetodo repaint, heredado indirectamente de la clase Component para indi-car que el PintaPanel debera ser refrescado en la pantalla tan pronto comosea posible con una llamada al metodo painComponent de PintaPanel.

El metodo paintComponent, lıneas 39–46, el cual recibe un parametroGraphics, es llamado automaticamente en cualquier momento que PaintPanelnecesite ser mostrado en la pantalla, como cuando la GUI es mostrada porprimera vez o refrescada en la pantalla, como cuando el metodo repaint esllamado o cuando el componente GUI fue ocultado por otra ventana en lapantalla y subsecuentemente se hace visible nuevamente.

1 // Pintar.java

Page 82: notasGUI

82 Componentes GUI

2 // Probando PintaPanel.

3 import java.awt.BorderLayout;

4 import javax.swing.JFrame;

5 import javax.swing.JLabel;

6

7 public class Pintar {

8

9 public static void main( String args[] ) {

10

11 // crear JFrame

12 JFrame application = new JFrame( "Un programa simple de pintado" );

13

14 PintaPanel pintaPanel = new PintaPanel(); // crear panel de pintado

15 application.add( pintaPanel, BorderLayout.CENTER ); // in center

16

17 // crear una etiqueta y colocarla en la parte SOUTH del BorderLayout

18 application.add( new JLabel( "Arrastrar el raton para dibujar" ),

19 BorderLayout.SOUTH );

20

21 application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

22 application.setSize( 400, 200 ); // fijar tama~no de ventana

23 application.setVisible( true ); // mostrar ventana

24 } // fin de main

25 } // fin de la clase Pintar

3.15. Manejo de eventos del teclado

Se presenta la interfaz KeyListener para manejar eventos del tecla-do. Los eventos del teclado son generados cuando las teclas del teclado sonpresionadas y soltadas. Una clase que implementa KeyListener debera dardeclaraciones para los metodos keyPressed, keyReleased y keyTyped, cadauno de los cuales recibe un KeyEvent como su argumento. La clase KeyEventes una subclase de InputEvent. El metodo keyPressed es llamado comorespuesta al presionar alguna tecla. El metodo keyTyped es llamado comorespuesta al presionar cualquier tecla que no sea una tecla de accion. Lasteclas de accion son Inicio, Fin, RePag, AvPag, Bloq Num, Despl, Pausa,Inter, Despl, Imp Pnt, Bloq May, teclas de funcion y teclas de navegaciondel cursor de texto. El metodo keyReleased es llamado cuando la tecla essoltada despues de cualquier evento keyPressed o keyTyped.

La siguiente aplicacion muestra los metodos de KeyListener. La claseVentanaDemoTecla implementa la interfaz KeyListener, por lo tanto los

Page 83: notasGUI

3.15 Manejo de eventos del teclado 83

tres metodos estan declarados en la aplicacion.

1 // VentanaDemoTecla.java

2 // Mostrando eventos de teclazos.

3 import java.awt.Color;

4 import java.awt.event.KeyListener;

5 import java.awt.event.KeyEvent;

6 import javax.swing.JFrame;

7 import javax.swing.JTextArea;

8

9 public class VentanaDemoTecla extends JFrame implements KeyListener {

10

11 private String linea1 = ""; // primera lınea del area de texto

12 private String linea2 = ""; // segunda lınea del area de texto

13 private String linea3 = ""; // tercera lınea del area de texto

14 private JTextArea areaTexto; // area de texto para mostrar la salida

15

16 // constructor VentanaDemoTecla

17 public VentanaDemoTecla() {

18

19 super( "Mostrando eventos de teclazos" );

20

21 areaTexto = new JTextArea( 10, 15 ); // configurar JTextArea

22 areaTexto.setText( "Presionar cualquier tecla del teclado..." );

23 areaTexto.setEnabled( false ); // deshabilitar el areaTexto

24 areaTexto.setDisabledTextColor( Color.BLACK ); // poner color del texto

25 add( areaTexto ); // agregar areaTexto al JFrame

26

27 addKeyListener( this ); // permitir a la ventana procesar los eventos de teclas

28 } // fin del constructor VentanaDemoTecla

29

30 // manejar tecla presionada

31 public void keyPressed( KeyEvent event ) {

32

33 linea1 = String.format( "Tecla presionada: %s",

34 event.getKeyText( event.getKeyCode() ) ); // salida de tecla presionada

35 setLineas2y3( event ); // poner lıneas de salida 2 y 3

36 } // fin del metodo keyPressed

37

38 // manejar tecla soltada

39 public void keyReleased( KeyEvent event ) {

40

41 linea1 = String.format( "Tecla soltada: %s",

42 event.getKeyText( event.getKeyCode() ) ); // salida de tecla soltada

43 setLineas2y3( event ); // poner lıneas de salida 2 y 3

44 } // fin del metodo keyReleased

Page 84: notasGUI

84 Componentes GUI

45

46 // manejar tecla accion presionada

47 public void keyTyped( KeyEvent event ) {

48

49 linea1 = String.format( "Tecla tecleada: %s", event.getKeyChar() );

50 setLineas2y3( event ); // poner lıneas de salida 2 y 3

51 } // fin del metodo keyTyped

52

53 // poner segunda y tercera lınea de salida

54 private void setLineas2y3( KeyEvent event ) {

55

56 linea2 = String.format( "Esta tecla %ses una tecla accion",

57 ( event.isActionKey() ? "" : "no " ) );

58

59 String temp = event.getKeyModifiersText( event.getModifiers() );

60

61 linea3 = String.format( "Teclas modificadoras presionadas: %s",

62 ( temp.equals( "" ) ? "none" : temp ) ); // modificadores de salida

63

64 areaTexto.setText( String.format( "%s\n%s\n%s\n",

65 linea1, linea2, linea3 ) ); // salida tres lıneas de texto

66 } // fin del metodo setLineas2y3

67 } // fin de la clase VentanaDemoTecla

1 // DemoTecla.java

2 // Probando VentanaDemoTecla.

3 import javax.swing.JFrame;

4

5 public class DemoTecla {

6

7 public static void main( String args[] ) {

8

9 VentanaDemoTecla ventanaDemoTecla = new VentanaDemoTecla();

10 ventanaDemoTecla.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaDemoTecla.setSize( 350, 100 ); // fijar tama~no de la ventana

12 ventanaDemoTecla.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase DemoTecla

El constructor, lıneas 17–28, registra la aplicacion para manejar sus pro-pios eventos del teclado usando el metodo addKeyListener en la lınea 27. Elmetodo addKeyListener esta declarado en la clase Component, por lo tantocada subclase de Component puede notificar objetos KeyListener de eventosdel teclado para ese componente.

Page 85: notasGUI

3.16 Manejadores de diseno 85

En la lınea 25, el constructor agrega areaTexto del tipo JTextArea alJFrame, donde la salida de la aplicacion es mostrada. Observar en la pantallaque areaTexto ocupa la ventana entera. Esto es debido a que el manejadopor defecto del JFrame es BorderLayour. Cuando un solo componente esagregado a un BorderLayout, el componente ocupa el contenedor entero. Enla lınea 24 se usa el metodo setDisabledTextColor para cambiar el colordel texto en el area de texto a negro.

El metodo keyPressed, lıneas 31–60 y el metodo keyReleased, lıneas39–44 usan el metodo getKeyCode de la clase KeyEvent para obtener el codi-go virtual de la tecla de la tecla que fue presionada. La clase KeyEvent

mantiene un conjunto de constantes—las constantes del codigo virtual deteclas—que representan cada tecla sobre el teclado. Estas constantes pue-den ser comparadas con el valor regresado por getKeyCode para probar te-clas individuales. El valor regresado por getKeyCode es pasado al metodogetKeyText de KeyEvent, el cual regresa una cadena conteniendo el nombrede la tecla que fue presionada. Para una lista completa de las constantes delcodigo virtual de teclas, revisar la documentacion para la clase KeyEvent.El metodo keyTyped, lıneas 47–51, usa el metodo getKeyChar de KeyEvent

para obtener el valor Unicode del caracter tecleado.

Los tres metodos manejadores de evento terminan llamando al metodosetLineas2y3, lıneas 54–66, y pasandole el objeto KeyEvent. Este metodousa isActionKey de KeyEvent para determinar si la tecla en el evento fue unatecla accion. Tambien, el metodo getModifiers de InputEvent es llamado,lınea 59, para determinar si algun modificador de teclas, tales como Cambio,Alt y Ctrl, fueron presionadas cuando el evento tecla ocurrio. El resultadode ese metodo es pasado al metodo getKeyModifiersText de KeyEvent, elcual produce una cadena conteniendo los nombres de las teclas modificadoraspresionadas.

3.16. Manejadores de diseno

Los manejadores de diseno son proporcionados para poner en ordenlos componentes GUI en un contenedor para propositos de presentacion. Losprogramadores puede usar los manejadores para capacidades de diseno basicoen vez de determinar la posicion exacta y tamano de cada componente GUI.Esta funcionalidad permite al programador concentrarse en la apariencia ycomportamiento basico y dejar al manejador de diseno el proceso de varios

Page 86: notasGUI

86 Componentes GUI

detalles del diseno. Todos los manejadores de diseno implementan la interfazLayoutManager del paquete java.awt. El metodo setLayout de la claseContainer toma un objeto que implementa la interfaz LayoutManager comoun argumento. Hay basicamente tres formas para arreglar los componentesen una GUI:

1. Posicionamiento absoluto: este propociona el mayor nivel de control so-bre la apariencia de la GUI. Poniendo el manejador de un Container

a null, se puede indicar la posicion absoluta de cada componente GUIcon respecto a la esquina superior izquierda del contenedor. Si se haceesto, se debe especificar de cada componente GUI su tamano. Progra-mar una GUI con posicionamiento absoluto puede ser tedioso, a menosque se tenga un ambiente integrado de desarrollo o IDE (IntegratedDevolpment Environment) que pueda generar el codigo por el progra-mador.

2. Manejador de diseno: usando manejadores de diseno para colocar ele-mentos puede ser mas simple y rapido que crear una GUI con posicio-namiento absoluto, pero se pierde algun control sobre el tamano y elposicionamiento preciso de los componentes GUI.

3. Programacion visual en una IDE: las IDEs dan herramientas que hacenfacil la creacion de GUIs. Cada IDE tıpicamente da una herramientade diseno GUI que permite arrastrar y soltar componentes GUI desdeuna caja de herramientas en una area de diseno. Se puede entonces loscomponentes posicionarlos, alinearlos y darles el tamano requerido deacuerdo con el programador. La IDE genera el codigo Java que creala GUI. Ademas, se puede tıpicamente agregar codigo de manejo deeventos para un componente particular haciendo doble pulsacion sobreel componente.

En la siguiente tabla se resumen los manejadores de diseno presentadosen este capıtulo.

Page 87: notasGUI

3.16 Manejadores de diseno 87

Manejador DescripcionFlowLayout Por defecto para javax.swing.JPanel.

Coloca los componentes secuencialmen-te, de izquierda a derecha en el orden enque fueron agregados. Tambien es posi-ble indicar el orden de los componentesusando el metodo add de Container, elcual toma un componente y una posicionde ındice entero como argumentos.

BorderLayout Por defecto para JFrame y otras venta-nas. Coloca los componentes en una decinco areas: NORTH, SOUTH, EAST, WEST yCENTER.

GridLayout Arregla los componentes en renglones ycolumnas.

3.16.1. FlowLayout

FlowLayout es el manejador de diseno mas simple. Los componentes GUIson colocados en un contenedor de izquierda a derecha conforme al orden enel cual fueron agregados al contenedor. Cuando una orilla del contenedores alcanzada, los componentes continuan mostrandose en la siguiente lınea.La clase FlowLayout permite a los componentes GUI estar alineados a laizquierda, al centro (por defecto) y a la derecha.

La siguiente aplicacion crea tres objetos JButton y los agrega a la apli-cacion, usando un manejador de diseno FlowLayout. Los componentes sonalineados al centro por defecto. Cuando el usuario pulsa Izquierda, la alinea-cion para el manejador de diseno cambia a la izquierda en el FlowLayout. Losotros dos botones alinean los componentes como se indica en la etiqueta delboton. Cada boton tiene su propio manejador de evento que esta declaradocon una clase interna que implementa ActionListener.

Un manejador de contenedor es puesto con el metodo setLayot de la claseContainer. La lınea 25 pone el manejador de diseno FlowLayout declaradoen la lınea 23. Normalmente, el manejador es puesto antes que cualquiercomponente GUI sea agregado al contenedor.

Cada manejador de evento de boton esta especificado con una objeto deuna clase interna anonima, lıneas 30–43, 48–61 y 66–71. Cada actionPer-formed de los manejadores de evento de los botones ejecuta dos sentencias.

Page 88: notasGUI

88 Componentes GUI

Por ejemplo, la lınea 37 en el metodo actionPerformed para el boton iz-quierdo usa el metodo setAlignment para cambiar a la izquierda la alinea-cion en el FlowLayout usando FlowLayout.LEFT. La lınea 40 usa el metodolayoutContainer de la interfaz LayoutManager, que es heredado por todoslos manejadores para indicar que el JFrame debera ser rearreglado de acuerdoal ajuste del manejador.

1 // VentanaFlowLayout.java

2 // Mostrando las alineaciones de FlowLayout.

3 import java.awt.FlowLayout;

4 import java.awt.Container;

5 import java.awt.event.ActionListener;

6 import java.awt.event.ActionEvent;

7 import javax.swing.JFrame;

8 import javax.swing.JButton;

9

10 public class VentanaFlowLayout extends JFrame {

11

12 private JButton botonIzq; // boton para alinear a la izquierda

13 private JButton botonCentr; // boton para alinear al centro

14 private JButton botonDer; // boton para alinear a la derecha

15 private FlowLayout manejador; // objeto manejador

16 private Container contenedor; // contenedor para poner manejador

17

18 // configurar la GUI y registrar los receptores para los botones

19 public VentanaFlowLayout() {

20

21 super( "Demo FlowLayout" );

22

23 manejador = new FlowLayout(); // crear FlowLayout

24 contenedor = getContentPane(); // obtener contenedor para el manejador

25 setLayout( manejador ); // poner manejador para la ventana

26

27 // configurar botonIzq y registrar receptor

28 botonIzq = new JButton( "Izquierda" ); // crear boton izquierda

29 add( botonIzq ); // agregar boton izquierda a la ventana

30 botonIzq.addActionListener(

31

32 new ActionListener() { // clase interna anonima

33

34 // procesar evento botonIzq

35 public void actionPerformed( ActionEvent event ) {

36

37 manejador.setAlignment( FlowLayout.LEFT );

38

Page 89: notasGUI

3.16 Manejadores de diseno 89

39 // realinear componentes adjuntos

40 manejador.layoutContainer( contenedor );

41 } // fin del metodo actionPerformed

42 } // fin de la clase interna anonima

43 ); // fin de la llamada addActionListener

44

45 // configurar botonCentr y registrar receptor

46 botonCentr = new JButton( "Centro" ); // crear boton central

47 add( botonCentr ); // agregar boton central a la ventana

48 botonCentr.addActionListener(

49

50 new ActionListener() { // clase interna anonima

51

52 // procesar evento botonCentr

53 public void actionPerformed( ActionEvent event ) {

54

55 manejador.setAlignment( FlowLayout.CENTER );

56 // realinear componentes adjuntos

57 manejador.layoutContainer( contenedor );

58 } // fin del metodo actionPerformed

59 } // fin de la clase interna anonima

60 ); // fin de la llamada addActionListener

61

62 // configurar botonDer y registrar receptor

63 botonDer = new JButton( "Derecha" ); // crear boton derecha

64 add( botonDer ); // agregar boton derecha a la ventana

65 botonDer.addActionListener(

66

67 new ActionListener() { // clase interna anonima

68

69 // procesar evento botonDer

70 public void actionPerformed( ActionEvent event ) {

71

72 manejador.setAlignment( FlowLayout.RIGHT );

73 // realinear componentes adjuntos

74 manejador.layoutContainer( contenedor );

75 } // fin del metodo actionPerformed

76 } // fin clase interna anonima

77 ); // fin de la llamada addActionListener

78 } // fin del constructo VentanaFlowLayout

79 } // fin de la clase VentanaFlowLayout

1 // DemoFlowLayout.java

2 // Probando VentanaFlowLayout.

3 import javax.swing.JFrame;

4

Page 90: notasGUI

90 Componentes GUI

5 public class DemoFlowLayout {

6

7 public static void main( String args[] ) {

8

9 VentanaFlowLayout ventanaFlowLayout = new VentanaFlowLayout();

10 ventanaFlowLayout.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaFlowLayout.setSize( 300, 75 ); // poner tama~no de la ventana

12 ventanaFlowLayout.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase DemoFlowLayout

3.16.2. BorderLayout

El manejador de diseno BorderLayout, el manejador por defecto para unJFrame, arregla los componentes en cinco regiones: NORTH, SOUTH, EAST,

WEST y CENTER. NORTH corresponde a la parte superior del contenedor. La claseBorderLayout extiende a Objecto e implementa la interfaz LayoutManager2,una subinterfaz de LayoutManager que agrega varios metodos para mejorarel procesamiento de diseno.

Un BorderLayout limita un Contenedor para tener a lo mas cinco compo-nentes—uno en cada region. El componente colocado en cada region puedeser un contenedor al cual esten otros componentes adjuntados. Los compo-nentes colocados en las regiones NORTH y SOUTH se extienden horizontalmentea los lados del contenedor y son tan altos como los componentes colocados enesas regiones. Las regiones EAST y WEST se expanden verticalmente entre lasregiones NORTH y SOUTH y son tan anchos como los componentes colocadosen esas regiones. El componente colocado en la region CENTER se expandepara ocupar todo el espacio restante en el diseno. Si las cinco regiones estanocupadas, el espacio entero del contenedor esta cubierto por componentesGUI. Si la region NORTH y SOUTH no estan ocupadas, los componentes GUIen las regiones EAST, CENTER y WEST se expanden verticalmente para ocuparel espacio restante. Si las regiones EAST y WEST no estan ocupadas, el com-ponente GUI en la region CENTER se expande horizontalmente para llenar elespacio restante. Si la region CENTER no esta ocupada, el area se deja vacıa—los otros componentes GUI no se expanden para llenar el espacio restante. Lasiguiente aplicacion muestra el manejador de diseno BorderLayout usandocinco JButtons.

1 // VentanaBorderLayout.java

2 // Mostrando BorderLayout.

Page 91: notasGUI

3.16 Manejadores de diseno 91

3 import java.awt.BorderLayout;

4 import java.awt.event.ActionListener;

5 import java.awt.event.ActionEvent;

6 import javax.swing.JFrame;

7 import javax.swing.JButton;

8

9 public class VentanaBorderLayout extends JFrame implements ActionListener {

10

11 private JButton botones[]; // arreglo de botones para ocultar porciones

12 private final String nombres[] = { "Ocultar Norte", "Ocultar Sur",

13 "Ocultar Este", "Ocultar Oeste", "Ocultar Centro" };

14 private BorderLayout manejador; // objeto borderlayout

15

16 // configurar GUI y manejadores de eventos

17 public VentanaBorderLayout() {

18

19 super( "Demo BorderLayout" );

20

21 manejador = new BorderLayout( 5, 5 ); // 5 pıxeles de abertura

22 setLayout( manejador ); // poner manejador a la ventana

23 botones = new JButton[ nombres.length ]; // crear arreglo de botones

24

25 // crear JButtons y registrar receptores para ellos

26 for ( int cont = 0; cont < nombres.length; cont++ ) {

27

28 botones[ cont ] = new JButton( nombres[ cont ] );

29 botones[ cont ].addActionListener( this );

30 } // fin for

31

32 add( botones[ 0 ], BorderLayout.NORTH ); // agregar boton al norte

33 add( botones[ 1 ], BorderLayout.SOUTH ); // agregar boton al sur

34 add( botones[ 2 ], BorderLayout.EAST ); // agregar boton al este

35 add( botones[ 3 ], BorderLayout.WEST ); // agregar boton al oeste

36 add( botones[ 4 ], BorderLayout.CENTER ); // agregar boton al centro

37 } // fin del constructor VentanaBorderLayout

38

39 // manejador de eventos del raton

40 public void actionPerformed( ActionEvent event ) {

41

42 // revisar la fuente del evento y disponer panel correspondiente

43 for ( JButton boton : botones ) {

44

45 if ( event.getSource() == boton )

46 boton.setVisible( false ); // ocultar el boton pulsado

47 else

Page 92: notasGUI

92 Componentes GUI

48 boton.setVisible( true ); // mostrar los otros botones

49 } // fin for

50

51 manejador.layoutContainer( getContentPane() ); // recalcular el contenido del cuadro

52 } // fin del metodo actionPerformed

53 } // fin de la clase VentanaBorderLayout

1 // DemoBorderLayout.java

2 // Probando VentanaBorderLayout.

3 import javax.swing.JFrame;

4

5 public class DemoBorderLayout {

6

7 public static void main( String args[] ) {

8

9 VentanaBorderLayout ventanaBorderLayout = new VentanaBorderLayout();

10 ventanaBorderLayout.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaBorderLayout.setSize( 300, 200 ); // fijar tama~no de la ventana

12 ventanaBorderLayout.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase DemoBorderLayout

La lınea 21 de la clase VentanaBorderLayout crea un BorderLayout. Losargumentos del constructor indican el numero de pıxeles entre los componen-tes que son arreglados horizontalmente (espacio de abertura horizontal)y entre los componentes que son arreglados verticalmente (espacio de aber-tura vertical), respectivamente. El valor por defecto es un pixel de espaciode abertura horizontal y vertical. La lınea 22 usa el metodo setLayout paraponer el manejador de diseno del panel.

Se agregan los componentes a un BorderLayout con otra version delmetodo add de la clase Container que toma dos argumentos—el componen-te a agregar y la region en la cual el componente debe aparecer. Por ejemplo,la lınea 32 indica que botones[0] debera aparecer en la region NORTH. Loscomponentes pueden ser agregados en cualquier orden, pero solamente uncomponente debera ser agregado a cada region. Cuando no se indica la re-gion donde sera agregado el componente a un BorderLayout, el manejadorsupone que debera ser puesto en la region CENTER. Cuando mas de un compo-nente es agreagado a una region, solamente el ultimo componente agregadosera mostrado.

La clase VentanaBorderLayout implementa ActionListener directamen-te en este ejemplo, por lo que la VentanaBorderLayout manejara los eventos

Page 93: notasGUI

3.16 Manejadores de diseno 93

de los JButtons. Por esta razon, la lınea 29 pasa la referencia this al metodoaddActionListener de cada JButton. Cuando el usuario pulsa un JButton

particular en el diseno, el metodo actionPerformed, lıneas 40–52, se ejecuta.La sentencia for mejorada en las lıneas 43–49 usa un if...else para ocultarel JButton particular que genero el evento. El metodo setVisible, heredadoen JButton desde la clase Component, es llamado con un argumento false,lınea 46 para ocultar el JButton. Si el JButton actual en el arreglo no esel que genero el evento, el metodo setVisible es llamado con el argumentotrue, lınea 48, para asegurar que el JButton es mostrado en la pantalla. Lalınea 51 usa el metodo layoutContainer de LayoutManager para recalcu-lar el diseno del contenido del cuadro. Con lo anterior ciertas regiones enel BorderLayout cambian de forma conforme los JButtons son ocultados ymostrados en otras regiones. Para disenos mas complejos, agrupar los com-ponentes en JPanels, cada uno con su propio manejador de diseno. Colocarlos JPanels en el JFrame usando el BorderLayout por defecto o algun otrodiseno.

3.16.3. GridLayout

El manejador de diseno GridLayout divide el contenedor en una cuadrıcu-la por lo que los componentes pueden ser colocados en renglones y columnas.La clase GridLayout hereda directamente de la clase Object e implementa lainterfaz LayoutManager. Cada componente en un GridLayout tiene el mis-mo ancho y alto. Los componentes son agregados a un GridLayout iniciandoen la celda de la esquina superior izquierda de la cuadrıcula y procediendode izquierda a derecha hasta que el renglon queda lleno. Entonces el procesocontinua de izquierda a derecha en el siguiente renglon de la cuadrıcula, yası sucesivamente. La siguiente aplicacion muestra el manejador de disenoGridLayout usando seis JButtons.

1 // VentanaGridLayout.java

2 // Mostrando GridLayout.

3 import java.awt.GridLayout;

4 import java.awt.Container;

5 import java.awt.event.ActionListener;

6 import java.awt.event.ActionEvent;

7 import javax.swing.JFrame;

8 import javax.swing.JButton;

9

10 public class VentanaGridLayout extends JFrame implements ActionListener {

Page 94: notasGUI

94 Componentes GUI

11

12 private JButton botones[]; // arreglo de botones

13 private final String nombres[] =

14 { "uno", "dos", "tres", "cuatro", "cinco", "seis" };

15 private boolean conmutador = true; // conmutador entre dos dise~nos

16 private Container contenedor; // contenedor de la ventana

17 private GridLayout gridLayout1; // primer gridlayout

18 private GridLayout gridLayout2; // segundo gridlayout

19

20 // constructor sin argumentos

21 public VentanaGridLayout() {

22

23 super( "Demo GridLayout" );

24 gridLayout1 = new GridLayout( 2, 3, 5, 5 ); // 2 x 3; espaciado de 5

25 gridLayout2 = new GridLayout( 3, 2 ); // 3 x 2; sin espaciado

26 contenedor = getContentPane(); // obtener contenido del cuadro

27 setLayout( gridLayout1 ); // poner el dise~no al JFrame

28 botones = new JButton[ nombres.length ]; // crear arreglo de JButtons

29

30 for ( int contador = 0; contador < nombres.length; contador++ ) {

31

32 botones[ contador ] = new JButton( nombres[ contador ] );

33 botones[ contador ].addActionListener( this ); // registrar receptor

34 add( botones[ contador ] ); // agregar boton al JFrame

35 } // fin for

36 } // fin del constructor VentanaGridLayout

37

38 // manejar los eventos del boton cambiando entre dise~nos

39 public void actionPerformed( ActionEvent event ) {

40

41 if ( conmutador )

42 contenedor.setLayout( gridLayout2 ); // poner 2◦ dise~no

43 else

44 contenedor.setLayout( gridLayout1 ); // poner 1er dise~no

45

46 conmutador = !conmutador; // poner conmutador a valor opuesto

47 contenedor.validate(); // redise~nar contenedor

48 } // fin del metodo actionPerformed

49 } // fin de la clase VentanaGridLayout

1 // DemoGridLayout.java

2 // Probando VentanaGridLayout

3 import javax.swing.JFrame;

4

5 public class DemoGridLayout {

6

Page 95: notasGUI

3.17 Paneles anidados 95

7 public static void main( String args[] ) {

8

9 VentanaGridLayout ventanaGridLayout = new VentanaGridLayout();

10 ventanaGridLayout.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaGridLayout.setSize( 300, 200 ); // fijar tama~no ventana

12 ventanaGridLayout.setVisible( true ); // mostrar ventana

13 } // fin del main

14 } // fin de la clase DemoGridLayout

3.17. Usando paneles para manejo de disenos

mas complejos

Para GUIs mas complejos se requiere que cada componente sea colocadoen una localidad exacta. Estos consisten de paneles multiples, con cada com-ponente del panel arreglado en diseno especıfico. La clase JPanel extiendea JComponent y JComponent extiende la clase Container, por lo que cadaJPanel es un contenedor. Por lo tanto, cada JPanel podrıa tener varios com-ponentes, incluyendo otros paneles, adjuntados a este con el metodo add deContainer. La siguiente aplicacion muestra como un JPanel puede ser usadopara crear un diseno mas complejo en el cual varios JButtons son colocadosen la region SOUTH de un BorderLayout.

Despues de que el panelBotones tipo JPanel es declarado en la lınea 11y creado en la lınea 19, la lınea 20 pone el diseno del panelBotones a unGridLayout de un renglon y cinco columnas. Las lıneas 23–27 agregan loscinco JButtons del arreglo botones al JPanel en el ciclo. La lınea 26 agregalos botones directamente al JPanel—la clase JPanel no tiene un cuadro decontenido, como un JFrame. La lınea 29 usa el BorderLayout por defectopara agregar el panelBotones a la region SOUTH. La region SOUTH es tanalta como los botones en panelBotones. Un JPanel es dimensionado a loscomponentes que este contiene. Conforme mas componentes sean agregados,el JPanel crece, de acuerdo a las restricciones de su manejador de diseno,para acomodar los componentes.

1 // VentanaPanel.java

2 // Usando un JPanel para ayudar al dise~no de los componentes

3 import java.awt.GridLayout;

4 import java.awt.BorderLayout;

5 import javax.swing.JFrame;

6 import javax.swing.JPanel;

Page 96: notasGUI

96 Componentes GUI

7 import javax.swing.JButton;

8

9 public class VentanaPanel extends JFrame {

10

11 private JPanel buttonJPanel; // panel que contendra los botones

12 private JButton botones[]; // arreglo de botones

13

14 // constructor sin argumentos

15 public VentanaPanel() {

16

17 super( "Demo Panel" );

18 botones = new JButton[ 5 ]; // crear arreglo de botones

19 buttonJPanel = new JPanel(); // crear panel

20 buttonJPanel.setLayout( new GridLayout( 1, botones.length ) );

21

22 // crear y agregar botones

23 for ( int contador = 0; contador < botones.length; contador++ ) {

24

25 botones[ contador ] = new JButton( "Boton " + ( contador + 1 ) );

26 buttonJPanel.add( botones[ contador ] ); // agregar boton al panel

27 } // fin del for

28

29 add( buttonJPanel, BorderLayout.SOUTH ); // add panel to JFrame

30 } // fin del constructor VentanaPanel

31 } // fin de la clase VentanaPanel

1 // DemoPanel.java

2 // Probando VentanaPanel.

3 import javax.swing.JFrame;

4

5 public class DemoPanel extends JFrame {

6

7 public static void main( String args[] ) {

8

9 VentanaPanel ventanaPanel = new VentanaPanel();

10 ventanaPanel.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaPanel.setSize( 450, 200 ); // fijar tama~no de la ventana

12 ventanaPanel.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase DemoPanel

Page 97: notasGUI

3.18 JTextArea 97

3.18. JTextArea

Un JTextArea da una area para manipular multiples lıneas de texto. Co-mo en la clase JTextField, JTextArea es una subclase de JTextComponent,la cual declara metodos comunes para JTextField y JTextArea y variosotros componentes GUI basados en texto.

La siguiente aplicacion muestra varios componentes JTextArea. Un JText-Area muestra texto que el usuario puede seleccionar. El otro JTextArea esno editable y es usado para mostrar el texto que el usario selecciono en elprimer JTextArea. Al igual que con las JLists de seleccion multiple, seccion3.10, un evento externo de otro componente GUI indica cuando se procesa eltexto en el JTextArea. Por ejemplo, cuando se teclea un correo electronico,normalmente se pulsa un boton Enviar para mandar el texto del mensaje alreceptor. Similarmente, cuando se edita un documento en procesador de pa-labras, normalmente se guarda el archivo seleccionando la opcion Guardaro Guardar como .... En este programa, el boton Copia )))) genera el eventoexterno que copia el texto seleccionado en el JTextArea de la izquierda y lomuestra en el de la derecha.

1 // VentanaTextArea.java

2 // Copiando texto seleccionado de una area de texto a otra.

3 import java.awt.event.ActionListener;

4 import java.awt.event.ActionEvent;

5 import javax.swing.Box;

6 import javax.swing.JFrame;

7 import javax.swing.JTextArea;

8 import javax.swing.JButton;

9 import javax.swing.JScrollPane;

10

11 public class VentanaTextArea extends JFrame {

12

13 private JTextArea textArea1; // mostrar texto demo

14 private JTextArea textArea2; // texto seleccionado es copiado aquı

15 private JButton jButtonCopiar; // inicia el copiado del texto

16

17 // constructor sin argumentos

18 public VentanaTextArea() {

19

20 super( "Demo de TextArea" );

21 Box caja = Box.createHorizontalBox(); // crear caja

22 String demo = "Esta es una cadena demo\n" +

23 "para mostrar el copiado de\ntexto de una area de texto a\n" +

Page 98: notasGUI

98 Componentes GUI

24 "otra area de texto usando\nun evento externo.\n";

25

26 textArea1 = new JTextArea( demo, 10, 15 ); // crear textarea1

27 caja.add( new JScrollPane( textArea1 ) ); // agregar scrollpane

28

29 jButtonCopiar = new JButton( "Copiar ))))" ); // crear boton copiar

30 caja.add( jButtonCopiar ); // agregar boton copiar a la caja

31 jButtonCopiar.addActionListener(

32

33 new ActionListener() { // clase anonima interna

34

35 // poner texto en textArea2 seleccionado en textArea1

36 public void actionPerformed( ActionEvent event ) {

37

38 textArea2.setText( textArea1.getSelectedText() );

39 } // fin del metodo actionPerformed

40 } // fin de la clase anonima interna

41 ); // fin de la llamada a addActionListener

42

43 textArea2 = new JTextArea( 10, 15 ); // crear segundo JTextarea

44 textArea2.setEditable( false ); // deshabilitar edicion

45 caja.add( new JScrollPane( textArea2 ) ); // agregar scrollpane

46

47 add( caja ); // agregar caja a la ventana

48 } // fin del constructor VentanaTextArea

49 } // fin de la clase VentanaTextArea

1 // DemoTextArea.java

2 // Copiando texto seleccionado de una area de texto a otra.

3 import javax.swing.JFrame;

4

5 public class DemoTextArea {

6

7 public static void main( String args[] ) {

8

9 VentanaTextArea ventanaTextArea = new VentanaTextArea();

10 ventanaTextArea.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaTextArea.setSize( 500, 200 ); // fijar tama~no de la ventana

12 ventanaTextArea.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase DemoTextArea

En el constructor, lıneas 18–48 de la clase VentanaTextArea, en la lınea21 se crea un contenedor Box del paquete javax.swing para organizar loscomponentes GUI. Box es una subclase de Container que usa un manejador

Page 99: notasGUI

3.19 Ejercicios 99

de diseno BoxLayout para arreglar los componentes GUI ya sea horizontal-mente o verticalmente. El metodo estatico createHorizontalBox de Box

crea una caja que arregla los componentes de izquierda a derecha en el ordenen el que fueron agregados.

Las lıneas 26 y 43 crean los JTextArea textArea1 y textArea2. La lınea26 usa el constructor de tres argumentos de JTextArea, el cual toma una ca-dena que representa el texto inicial y dos enteros indicando que el JTextAreatiene 10 renglones y 15 columnas. La lınea 43 un constructor de dos argu-mentos de JTextArea, indicando que el JTextArea tiene 10 renglones y 15columnas. La lınea 26 indica que demo debera ser mostrado como el conte-nido por defecto del JTextArea. Un JTextArea no proporciona barras dedesplazamiento si no puede mostrar su contenido completo. Por lo tanto, lalınea 27 crea un objeto JScrollPane, lo inicializa con textArea1 y lo agregaal contenedor caja. Por defecto, las barras de desplazamiento horizontal yvertical apareceran cuando sean necesarias en un JScrollPane.

Las lıneas 29–41 crean un objeto JButton jButtonCopiar con la etique-ta “Copiar ))))”, lo agregan al contenedor caja y le registran un maneja-dor de eventos para ActionEvent. Este boton proporciona el evento externoque determina cuando el programa debera copiar el texto seleccionado entextArea1 a textArea2. Cuando el usuario pulsa jButtonCopiar, la lınea38 en actionPerformed indica que el metodo getSelectedText, heredadoen JTextArea desde JTextComponent, debera regresar el texto seleccionadode textArea1. El usuario selecciona texto arrastrando el raton sobre el textodeseado para resaltarlo. El metodo setText cambia el texto en textArea2

con la cadena que es regresada por getSelectedText.

Las lıneas 43–45 crean textArea2, ponen su propiedad editable a false

y lo agregan al contenedor caja. La lınea 47 agrega caja al JFrame.

3.19. Ejercicios

1. Disenar la siguiente calculadora y darle la funcionalidad requerida. Losbotones para escoger el estilo del cuadro de texto deberan ser del tipoJCheckBox y los botones para seleccionar el tamano de la fuente delcuadro de texto seran tipo JRadioButton.

Page 100: notasGUI

100 Componentes GUI

2. Para el ejemplo en donde se usa una subclase JPanel para dibujar conel raton en la seccion 3.14, agregar las siguientes opciones:

a) Pintar con diferentes colores.

b) Tamano variable de la brocha.

c) Usar diferentes tipos de figuras, como rectangulos, lıneas vertica-les, lıneas horizontales o elipses.

d) Figuras rellenas o huecas.

3.20. Usando Menus con Frames

Los menus son una parte integral de las GUIs. Los menus permiten alusuario realizar acciones sin necesidad de saturar una GUI con componen-tes extras. Los menus simplifican las GUIs porque los componentes puedenestar escondidos dentro de ellos. Estos componentes seran visibles solamen-te cuando el usuario los busque seleccionando el menu. En las GUI Swing,los menus solo pueden ser adjuntados a objetos de las clases que dan elmetodo setJMenuBar. Tales clase son JFrame y JApplet. Las clases usadaspara declarar menus son JMenuBar, JMenu, JMenuItem, JCheckBoxMenuItemy JRadioButtonMenuItem.

La clase JMenuBar, una subclase de JComponent, contiene los metodosnecesarios para manejar una barra de menus, la cual es un contenedor paramenus. La clase JMenu, una subclase de javax.swing.JMenuItem, contienelos metodos necesarios para manejar menus. Los menus contienen elementosmenu y son agregados a las barras de menus o a otros menus como sub-menus. Cuando un menu es pulsado, este se expande para mostrar su listade elementos menu.

La clase JMenuItem, una subclase de javax.swing.AbstractButton, con-tiene los metodos necesarios para manejar elementos menu. Un elemento

Page 101: notasGUI

3.20 Usando Menus con Frames 101

menu es un componente GUI dentro de un menu que, cuando es selecciona-do, causa un evento accion. Un elemento menu puede ser usado para iniciaruna accion, o este puede ser un submenu que proporcione mas elementosmenu que el usuario puede seleccionar. Los submenus son utiles para agru-par elementos menu relacionados en un menu.

La clase JCheckBoxMenuItem, una subclase de javax.swing.JMenuItem,contiene los metodos necesarios para manejar elementos menu que puedenser activar o desactivar. Cuando un JCheckBoxMenuItem es seleccionado, unamarca aparece a la izquierda del elemento menu. Cuando el JCheckBoxMenuItemes seleccionado nuevamente, la marca es removida.

La clase JRadioButtonMenuItem, una subclase de javax.swing.JMenuItemcontiene los metodos necesarios para manejar elementos menu que pueden seractivados o desactivados, parecido a JCheckBoxMenuItem. Cuando multiplesJRadioButtonMenuItem son mantenidos como para de un ButtonGroup, sola-mente un elemento en el grupo puede ser seleccionado, un cırculo relleno apa-rece a la izquierda del elemento menu. Cuando otro JRadioButtonMenuItem

es seleccionado, el cırculo relleno del menu item seleccionado es removido.La siguiente aplicacion muestra varios elementos menu y como especificar

los caracteres especiales llamados mnemonicos que pueden proporcionar ac-ceso rapido a un menu o un elemento menu desde el teclado. Los mnemonicospueden ser usados con todas las subclases javax.swing.AbstractButton.

La clase VentanaMenu declara los componentes GUI y el manejo de even-tos para los elementos menu. La mayorıa del codigo en esta aplicacion apareceen el constructor de la clase (lıneas 34-151).

1 // VentanaMenu.java

2 // Usando menus.

3 import java.awt.Color;

4 import java.awt.Font;

5 import java.awt.BorderLayout;

6 import java.awt.event.ActionListener;

7 import java.awt.event.ActionEvent;

8 import java.awt.event.ItemListener;

9 import java.awt.event.ItemEvent;

10 import javax.swing.JFrame;

11 import javax.swing.JRadioButtonMenuItem;

12 import javax.swing.JCheckBoxMenuItem;

13 import javax.swing.JOptionPane;

14 import javax.swing.JLabel;

15 import javax.swing.SwingConstants;

16 import javax.swing.ButtonGroup;

Page 102: notasGUI

102 Componentes GUI

17 import javax.swing.JMenu;

18 import javax.swing.JMenuItem;

19 import javax.swing.JMenuBar;

20

21 public class VentanaMenu extends JFrame {

22

23 private final Color valoresColor[] =

24 { Color.BLACK, Color.BLUE, Color.RED, Color.GREEN };

25 private JRadioButtonMenuItem elemsColor[]; // elementos menu color

26 private JRadioButtonMenuItem fuentes[]; // elementos menu fuente

27 private JCheckBoxMenuItem elemsEstilo[]; // elementos menu estilo de fuente

28 private JLabel mostrarJLabel; // muestra texto ejemplo

29 private ButtonGroup grupoBotonFuente; // maneja elementos menu fuente

30 private ButtonGroup grupoBotonColor; // manenja elementos menu color

31 private int estilo; // usada para crear estilos para fuentes

32

33 // constructor sin argumentos para configurar GUI

34 public VentanaMenu() {

35

36 super( "Usando JMenus" );

37

38 JMenu menuArch = new JMenu( "Archivo" ); // crear menu archivo

39 menuArch.setMnemonic( ’A’ ); // poner mnemonico a A

40

41 // crear elemento menu Acerca de ...

42 JMenuItem elemAcerca = new JMenuItem( "Acerca de ..." );

43 elemAcerca.setMnemonic( ’C’ ); // poner mnemonico a c

44 menuArch.add( elemAcerca ); // agregar elemento acerca al menu archivo

45 elemAcerca.addActionListener(

46

47 new ActionListener() { // clase interna anonima

48

49 // mostrar mensaje de dialogo cuando el usuario selecciona Acerca de ...

50 public void actionPerformed( ActionEvent evento ) {

51

52 JOptionPane.showMessageDialog( VentanaMenu.this,

53 "Este es un ejemplo\ndel uso de menus.",

54 "Acerca de", JOptionPane.PLAIN_MESSAGE );

55 } // fin del metodo actionPerformed

56 } // fin de la clase anonima interna

57 ); // fin de la llamada a addActionListener

58

59 JMenuItem elemSalir = new JMenuItem( "Salir" ); // crear elemento salir

60 elemSalir.setMnemonic( ’s’ ); // poner mnemonico a s

61 menuArch.add( elemSalir ); // agregar elemento salir al menu archivo

Page 103: notasGUI

3.20 Usando Menus con Frames 103

62 elemSalir.addActionListener(

63

64 new ActionListener() { // clase anonima interna

65

66 // terminar la aplicacion cuando el usuario pulse elemSalir

67 public void actionPerformed( ActionEvent evento ) {

68

69 System.exit( 0 ); // exit application

70 } // fin del metodo actionPerformed

71 } // fin de la clase anonima interna

72 ); // fin de la llamada a addActionListener

73

74 JMenuBar barra = new JMenuBar(); // crear barra de menus

75 setJMenuBar( barra ); // agregar barra de menus a la la aplicacion

76 barra.add( menuArch ); // agregar menu archivo a la barra de menus

77

78 JMenu menuFormato = new JMenu( "Formato" ); // crear menu formato

79 menuFormato.setMnemonic( ’F’ ); // poner mnemonico a F

80

81 // arreglo listando las cadenas de colores

82 String colores[] = { "Negro", "Azul", "Rojo", "Verde" };

83

84 JMenu menuColor = new JMenu( "Color" ); // crear menu color

85 menuColor.setMnemonic( ’C’ ); // poner mnemonico a C

86

87 // crear arreglo para elementos menu botones de radio para colores

88 elemsColor = new JRadioButtonMenuItem[ colores.length ];

89 grupoBotonColor = new ButtonGroup(); // manejar colores

90 ManejadorElemento manejadorElemento = new ManejadorElemento(); // manejador para colores

91

92 // crear elementos menu botones de radio

93 for ( int contador = 0; contador < colores.length; contador++ ) {

94

95 elemsColor[ contador ] =

96 new JRadioButtonMenuItem( colores[ contador ] ); // crear elemento

97 menuColor.add( elemsColor[ contador ] ); // agregar elemento al menu color

98 grupoBotonColor.add( elemsColor[ contador ] ); // agregar al grupo

99 elemsColor[ contador ].addActionListener( manejadorElemento );

100 } // fin del for

101

102 elemsColor[ 0 ].setSelected( true ); // marcar el primer elemento

103

104 menuFormato.add( menuColor ); // agregar menu color al menu formato

105 menuFormato.addSeparator(); // agregar separador en el menu

106

Page 104: notasGUI

104 Componentes GUI

107 // arreglo listando los nombres de las fuentes

108 String nombresFuentes[] = { "Serif", "Monospaced", "SansSerif" };

109 JMenu menuFuente = new JMenu( "Fuente" ); // crear menu fuente

110 menuFuente.setMnemonic( ’u’ ); // poner mnemonico a u

111

112 // crear elementos menu botones de radio para las fuentes

113 fuentes = new JRadioButtonMenuItem[ nombresFuentes.length ];

114 grupoBotonFuente = new ButtonGroup(); // maneja nombres de fuentes

115

116 // crear elementos menu fuente boton de radio

117 for ( int contador = 0; contador < fuentes.length; contador++ ) {

118

119 fuentes[ contador ] = new JRadioButtonMenuItem( nombresFuentes[ contador ] );

120 menuFuente.add( fuentes[ contador ] ); // agregar fuente al menu fuente

121 grupoBotonFuente.add( fuentes[ contador ] ); // agregar al grupo

122 fuentes[ contador ].addActionListener( manejadorElemento ); // add handler

123 } // fin for

124

125 fuentes[ 0 ].setSelected( true ); // seleccionar primer elemento del menu fuente

126 menuFuente.addSeparator(); // agrear separador al menu fuente

127

128 String nombresEstilos[] = { "Negrita", "Italica" }; // nombres de estilos

129 elemsEstilo = new JCheckBoxMenuItem[ nombresEstilos.length ];

130 ManejadorEstilo manejadorEstilo = new ManejadorEstilo(); // manejador de estilos

131

132 // crear elementos menu estilo tipo verificacion

133 for ( int contador = 0; contador < nombresEstilos.length; contador++ ) {

134

135 elemsEstilo[ contador ] =

136 new JCheckBoxMenuItem( nombresEstilos[ contador ] ); // crear elemento

137 menuFuente.add( elemsEstilo[ contador ] ); // agregar al menu fuente

138 elemsEstilo[ contador ].addItemListener( manejadorEstilo ); // manejador

139 } // fin del for

140

141 menuFormato.add( menuFuente ); // agregar menu fuente al menu formato

142 barra.add( menuFormato ); // agregar menu Formato a la barra de menus

143

144 // configurar etiqueta que mostrara el texto

145 mostrarJLabel = new JLabel( "Texto Ejemplo", SwingConstants.CENTER );

146 mostrarJLabel.setForeground( valoresColor[ 0 ] );

147 mostrarJLabel.setFont( new Font( nombresFuentes[ 0 ], Font.PLAIN, 72 ) );

148

149 getContentPane().setBackground( Color.CYAN ); // fijar fondo

150 add( mostrarJLabel, BorderLayout.CENTER ); // agregar mostrarJLabel

151 } // fin del constructor VentanaMenu

Page 105: notasGUI

3.20 Usando Menus con Frames 105

152

153 // clase interna para manejar los eventos accion de los elementos menu.

154 private class ManejadorElemento implements ActionListener {

155

156 // procesar selecciones color y fuente

157 public void actionPerformed( ActionEvent evento ) {

158

159 // procesar seleccion de color

160 for ( int contador = 0; contador < elemsColor.length; contador++ ) {

161

162 if ( elemsColor[ contador ].isSelected() ) {

163

164 mostrarJLabel.setForeground( valoresColor[ contador ] );

165 break;

166 } // fin del if

167 } // fin del for

168

169 // procesar seleccion de fuente

170 for ( int contador = 0; contador < fuentes.length; contador++ ) {

171

172 if ( evento.getSource() == fuentes[ contador ] ) {

173

174 mostrarJLabel.setFont(

175 new Font( fuentes[ contador ].getText(), estilo, 72 ) );

176 } // fin del if

177 } // fin del for

178

179 repaint(); // redibujar la aplicacion

180 } // fin del metodo actionPerformed

181 } // fin de la clase ManejadorElemento

182

183 // clase interna para manejar los eventos de los elementos menu verificacion

184 private class ManejadorEstilo implements ItemListener {

185

186 // procesar selecciones estilo de fuente

187 public void itemStateChanged( ItemEvent e ) {

188

189 estilo = 0; // inicializar estilo

190

191 // revisar por seleccion negrita

192 if ( elemsEstilo[ 0 ].isSelected() )

193 estilo += Font.BOLD; // agregar negrita a estilo

194

195 // revisar por seleccion italica

196 if ( elemsEstilo[ 1 ].isSelected() )

Page 106: notasGUI

106 Componentes GUI

197 estilo += Font.ITALIC; // agregar italica a estilo

198

199 mostrarJLabel.setFont(

200 new Font( mostrarJLabel.getFont().getName(), estilo, 72 ) );

201 repaint(); // redibujar aplicacion

202 } // fin del metodo itemStateChanged

203 } // fin de la clase ManejadorEstilo

204 } // fin de la clase VentanaMenu

Las lıneas 38–76 configuran el menu Archivo y lo adjuntan a la barrade menus. El menu Archivo contiene el elemento menu Acerca de ... quemuestra un mensaje de dialogo cuando el elemento menu es seleccionado yel elemento menu Salir puede ser seleccionado para terminar la aplicacion.

La lınea 38 crea un JMenu y pasa al constructor la cadena “Archivo”como el nombre del menu. La lınea 39 usa de JMenu el metodo setMnemonic

para indicar que A es el mnemonico para este menu. Presionando la teclaAlt y la letra A se abre el menu, como si se hubiese pulsado con el ratonen el nombre del menu. En la GUI, el caracter mnemonico en el nombre delmenu es mostrado subrayado.

Las lıneas 42–43 crean el elemAcerca del tipo JMenuItem con el texto“Acerca de ...” y pone su mnemonico a la letra c. Este elemento menu esagregado a menuArch en la lınea 44 con el metodo add de JMenu. Las lıneas 47–56 crean un ActionListener para procesar los eventos accion de elemAcerca.Las lıneas 52-54 muestran un mensaje cuadro de dialogo. En los primeros usosde showMessageDialog, el primer argumento era null. El proposito del pri-mer argumento es para especificar la ventana padre que ayuda a determinardonde el cuadro de dialogo sera desplegado. Si la ventana padre es indicadacomo null, el cuadro de dialogo aparece en el centro de la ventana. De otraforma, este aparece centrado sobre la ventana padre especificada. En esteejemplo, el programa indica la ventana padre con VentanaMenu.this—la re-ferencia this del objeto VentanaMenu. Cuando se usa la referencia this enuna clase interna, indicando this se refiere al objeto de la clase interna. Parareferir al objeto this de la clase exterior, calificar this con el nombre de laclase exterior y un punto (.).

Los cuadros de dialogo son tıpicamente modales. Un cuadro de dialogomodal no permite que ninguna otra aplicacion en la ventana sea accedidahasta que el cuadro de dialogo sea descartado. Los cuadros de dialogo mostra-dos con la clase JOptionPane son dialogos modales. La clase JDialog puedeser usada para crear dialogos modales o no modales.

Page 107: notasGUI

3.20 Usando Menus con Frames 107

Las lıneas 59–72 crean el elemento menu elemSalir, ponen su mnemonicoa S, lo agregan a menuArch y registran un ActionListener que termina laaplicacion cuando el usuario selecciona elemSalir.

Las lıneas 74–76 crean un JMenuBar, la adjuntan a la ventana aplicacioncon el metodo setJMenuBar de JFrame y usan el metodo add de JMenuBar

para adjuntar menuArch al JMenuBar.Las lıneas 78–79 crean el menu menuFormato y ponen su mnemonico a F.Las lıneas 84–85 crean el menu menuColor, que sera un submenu del

menu Formato y pone su mnemonico a C. La lınea 88 crea el arreglo elemsColordel tipo JRadioButtonMenuItem, el cual se refiere a los elementos menu enmenuColor. La lınea 89 crea grupoBotonColor tipo ButtonGroup, el cualasegurara que solamente uno de los elementos menu en el submenu Color

este seleccionado a la vez. La lınea 90 crea una instancia de la clase in-terna ManejadorElemento, declarada en las lıneas 154–181, que respondea selecciones de los submenus Color o Fuente. La sentencia for en laslıneas 93–100 crea cada JRadioButtonMenuItem del arreglo elemsColor,agrega cada elemento menu a menuColor y a grupoBotonColor y registra elActionListener para cada elemento menu.

La lınea 102 invoca al metodo setSelected para seleccionar el primerelemento en el arreglo elemsColor. La lınea 104 agrega menuColor como unsubmenu de menuFormato. La lınea 105 invoca al metodo addSeparator deAbstractButton para agregar un lınea separadora horizontal al menu.

Las lıneas 108–126 crean el submenu Fuente y varios JRadioButtonMenu-Item y seleccionan el primer elemento del arreglo fuentes de tipo JRadio-ButtonMenuItem. La lınea 129 crea un arreglo JCheckBoxMenuItem para re-presentar los elementos menu para indicar los estilos negrita e italica para lasfuentes. La lınea 130 crea una instancia de la clase interna ManejadorEstilo,declarada en las lıneas 184–203, para responder a los eventos JCheckBoxMenu-Item. La sentencia for en las lıneas 133–139 crea cada JCheckBoxMenuItem,agrega cada elemento menu a menuFuente y registra el ItemListener paracada elemento menu. La lınea 141 agrega menuFuente como un submenu demenuFormato. La lınea 142 agrega el menuFormato a la barra de menus.

Las lıneas 145–147 crean un JLabel del que se controla la fuente, el colory el estilo con los elementos menu del menu Formato. El color inicial de lafuente es puesto con el primer elemento del arreglo valoresColor invocandoal metodo setForeground de JComponent, y la fuente incial es puesta aSerif con estilo PLAIN y de 72 puntos de tamano. La lınea 148 pone el colorde fondo del contenido de la ventana a cian, y la lınea 150 agrega el JLabel

Page 108: notasGUI

108 Componentes GUI

al centro de la ventana.

El metodo actionPerformed de ManejadorElemento en las lıneas 157–180, usa dos sentencia for para determinar cual elemento menu fuente ocolor genero el evento y poner la fuente o color de mostrarJLabel. La condi-cion if en la lınea 162 usa el metodo isSelected de AbstractButton paradeterminar el JRadioButtonMenuItem seleccionado. La condicion if en lalınea 172 invoca al metodo getSource del objeto evento para obtener unareferencia al JRadioButtonMenuItem que genero el evento. La lınea 175 in-voca al metodo getText de AbstractButton para obtener el nombre de lafuente del elemento menu.

El programa llama al metodo itemStateChanged de ManejadorEstilo,lıneas 187–202, si el usuario selecciona un JCheckBoxMenuItem en el menuFuente.Las lıneas 192 y 196 determinan cual de los dos JCheckBoxMenuItems estanseleccionados y usan sus estados combinados para determinar el nuevo estilode la fuente.

1 // PruebaMenu.java

2 // Usando VentanaMenu.

3 import javax.swing.JFrame;

4

5 public class PruebaMenu {

6

7 public static void main( String args[] ) {

8

9 VentanaMenu ventanaMenu = new VentanaMenu(); // crear VentanaMenu

10 ventanaMenu.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaMenu.setSize( 600, 200 ); // fijar tama~no de la ventana

12 ventanaMenu.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase PruebaMenu

3.21. JPopupMenu

Varias de las aplicaciones para computadoras actuales proporcionan losmenus emergentes sensitivos al contexto. En Swing, tales menus soncreados con la clase JPopupMenu, una subclase de JComponent. Estos menusproporcionan opciones que son especıficas al componente que genero el even-to disparador emergente. En varios sistemas, el evento disparador emer-gente ocurre cuando el usuario presiona y suelta el boton derecho del raton.

Page 109: notasGUI

3.21 JPopupMenu 109

La aplicacion de esta seccion crea un JPopupMenu que permite al usuarioseleccionar uno de tres colores para cambiar el color del fondo de la ventana.Cuando el usuario pulsa el boton derecho del raton sobre el fondo de la ven-tana PruebaPopup, un JPopupMenu conteniendo colores aparece. Si el usuariopulsa un JRadioButtonMenuItem para un color, el metodo actionPerformed

de ManejadorElemento cambia el color del fondo del panel de la ventana.

1 // VentanaPopup.java

2 // Mostrando JPopupMenus.

3 import java.awt.Color;

4 import java.awt.event.MouseAdapter;

5 import java.awt.event.MouseEvent;

6 import java.awt.event.ActionListener;

7 import java.awt.event.ActionEvent;

8 import javax.swing.JFrame;

9 import javax.swing.JRadioButtonMenuItem;

10 import javax.swing.JPopupMenu;

11 import javax.swing.ButtonGroup;

12

13 public class VentanaPopup extends JFrame {

14

15 private JRadioButtonMenuItem elems[]; // mantiene elementos para colores

16 private final Color colores[] =

17 { Color.BLUE, Color.YELLOW, Color.RED }; // colores que seran usados

18 private JPopupMenu menuEmergente; // permite al usuario seleccionar color

19

20 // constructor sin argumentos para configurar GUI

21 public VentanaPopup() {

22

23 super( "Usando JPopupMenus" );

24

25 ManejadorElemento manejador = new ManejadorElemento(); // manejador para menu elems

26 String nombColores[] = {"Azul","Amarillo","Rojo" }; // arreglo de nombres de Colores

27

28 ButtonGroup colorGroup = new ButtonGroup(); // maneja los elementos color

29 menuEmergente = new JPopupMenu(); // crear menu emergente

30 elems = new JRadioButtonMenuItem[ 3 ]; // elementos para seleccionar color

31

32 // construir elemento menu, agregarlo al menu, habilitar manejo de eventos

33 for ( int cont = 0; cont < elems.length; cont++ ) {

34

35 elems[ cont ] = new JRadioButtonMenuItem( nombColores[ cont ] );

36 menuEmergente.add( elems[ cont ] ); // agregar elemento al menu emergente

37 colorGroup.add( elems[ cont ] ); // agregar elemento al grupo boton

38 elems[ cont ].addActionListener( manejador ); // agregar manejador

Page 110: notasGUI

110 Componentes GUI

39 } // fin del for

40

41 getContentPane().setBackground( Color.WHITE ); // poner fondo blanco

42

43 // declarar un MouseListener para la ventana para mostrar menu emergente

44 addMouseListener(

45

46 new MouseAdapter() { // clase anonima interna

47

48 // manejar evento raton presionado

49 public void mousePressed( MouseEvent event ) {

50

51 revisarPorEventoDisparado( event ); // revisar por disparo

52 } // fin del metodo mousePressed

53

54 // manejar evento raton liberado

55 public void mouseReleased( MouseEvent event ) {

56

57 revisarPorEventoDisparado( event ); // revisar por disparo

58 } // fin del metodo mouseReleased

59

60 // determinar si el evento debera mostrar menu emergente

61 private void revisarPorEventoDisparado( MouseEvent event ) {

62

63 if ( event.isPopupTrigger() )

64 menuEmergente.show(

65 event.getComponent(), event.getX(), event.getY() );

66 } // fin del metodo revisarPorEventoDisparado

67 } // fin de la clase anonima

68 ); // fin de la llamada a addMouseListener

69 } // fin del constructor VentanaPopup

70

71 // clase interna privada para manejar los eventos de elementos menu

72 private class ManejadorElemento implements ActionListener {

73

74 // procesar las selecciones de elementos menu

75 public void actionPerformed( ActionEvent event ) {

76

77 // determinar cual elemento menu fue seleccionado

78 for ( int i = 0; i < elems.length; i++ ) {

79

80 if ( event.getSource() == elems[ i ] ) {

81

82 getContentPane().setBackground( colores[ i ] );

83 return;

Page 111: notasGUI

3.21 JPopupMenu 111

84 } // fin del if

85 } // fin del for

86 } // fin del metodo actionPerformed

87 } // fin de la clase privada interna ManejadorElemento

88 } // fin de la clase VentanaPopup

La lınea 25, en el constructor VentanaPopup de las lıneas 21–69, creauna instancia de la clase ManejadorElemento, que esta declarado en laslıneas 72–87, para procesar los eventos elemento de los elementos menu en elmenu emergente. La lınea 29 crea el JPopupMenu. La sentencia for, lıneas 33–39, crea un objeto JRadioButtonMenuItem, lınea 35, lo agrega al menu emer-gente en la lınea 36, lo agrega a grupoColor del tipo ButtonGroup en la lınea37 para mantener un solo JRadioButtonMenuItem seleccionada a la vez y re-gistra su ActionListener en la lınea 38. La lınea 41 pone el fondo inicial ablanco invocando el metodo setBackground.

Las lıneas 44–68 registran un MouseListener para manejar los eventosraton de la ventana de aplicacion. Los metodos mousePressed, lıneas 49–52,y mouseReleased, lıneas 55–58 revisan el evento disparador emergente. Ca-da metodo llama al metodo utilidad privado revisarPorEventoDisparado,lıneas 61–66, para determinar si ocurrio un evento disparador emergente. Sieste sucedio, el metodo isPopupTrigger de MouseEvent regresa true, y elmetodo show de JPopupMenu muestra el JPopupMenu. El primer argumen-to al metodo show indica el componente origen, cuya posicion ayuda adeterminar donde el JPopupMenu aparecera en la pantalla, los ultimos dosargumentos son las coordenadas xy, medidas desde la esquina superior iz-quierda del componente origen, en el cual el JPopupMenu aparecera.

Cuando el usuario selecciona un elemento menu de menu emergente, elmetodo actionPerformed de la clase ManejadorElemento, lıneas 75–86, de-termina cual JRadioButtonMenuItem el usuario selecciono y pone el colordel fondo del panel de la ventana.

1 // PruebaPopup.java

2 // Probando VentanaPopup.

3 import javax.swing.JFrame;

4

5 public class PruebaPopup {

6

7 public static void main( String args[] ) {

8

9 VentanaPopup ventanaPopup = new VentanaPopup(); // crear VentanaPopup

10 ventanaPopup.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

Page 112: notasGUI

112 Componentes GUI

11 ventanaPopup.setSize( 300, 200 ); // fijar tama~no de la ventana

12 ventanaPopup.setVisible( true ); // mostrar ventana

13 } // fin del main

14 } // fin de la clase PruebaPopup

3.22. JTabbedPane

Un JTabbedPane arregla los componentes GUI en capas, de las cualessolo una es visible a la vez. Los usuarios acceden cada capa mediante unapestana—parecida a las carpertas en un archivero. Cuando el usuario pulsauna pestana, la capa apropiada es mostrada. Las pestanas aparecen en laparte superior por defecto pero pueden ser posicionadas a la izquierda, dere-cha o abajo del JTabbedPane. Cualquier componente puede ser colocado enuna pestana. Si el componente es un contenedor, como un panel, este puedeusar cualquier manejador de diseno para acomodar varios componentes en lapestana. La clase JTabbedPane es una subclase de JComponent. La siguien-te aplicacion crea una ventana de pestanas con tres de estas. Cada pestanamuestra uno de los JPanel—panel1, panel2, y panel3 y sus componentesGUI.

1 // VentanaJTabbedPane.java

2 // Demostrando JTabbedPane.

3 import java.awt.BorderLayout;

4 import java.awt.Color;

5 import javax.swing.JFrame;

6 import javax.swing.JTabbedPane;

7 import javax.swing.JLabel;

8 import javax.swing.JPanel;

9 import javax.swing.JButton;

10 import javax.swing.SwingConstants;

11

12 public class VentanaJTabbedPane extends JFrame {

13

14 // configurar GUI

15 public VentanaJTabbedPane() {

16

17 super( "Demo JTabbedPane" );

18

19 JTabbedPane panelPesta~nas = new JTabbedPane(); // crear JTabbedPane

20

21 // configurar pane11 y agregarlo al JTabbedPane

Page 113: notasGUI

3.22 JTabbedPane 113

22 JLabel etiq1 = new JLabel( "panel uno", SwingConstants.CENTER );

23 JPanel panel1 = new JPanel(); // crear primer panel

24 panel1.add( etiq1 ); // agregar etiqueta a panel

25 panelPesta~nas.addTab( "Pesta~na Uno", null, panel1, "Primer Panel" );

26

27 // configurar pane12 y agregarlo al JTabbedPane

28 JLabel label2 = new JLabel( "panel dos", SwingConstants.CENTER );

29 JPanel panel2 = new JPanel(); // crear segundo panel

30 panel2.setBackground( Color.YELLOW ); // poner fondo amarillo

31 panel2.add( label2 ); // agregar etiqueta a panel

32 panelPesta~nas.addTab( "Pesta~na Dos", null, panel2, "Segundo Panel" );

33

34 // configurar pane13 y agregarlo al JTabbedPane

35 JLabel label3 = new JLabel( "panel tres" );

36 JPanel panel3 = new JPanel(); // crear tercer panel

37 panel3.setLayout( new BorderLayout() ); // usar borderlayout

38 panel3.add( new JButton( "Norte" ), BorderLayout.NORTH );

39 panel3.add( new JButton( "Oeste" ), BorderLayout.WEST );

40 panel3.add( new JButton( "Este" ), BorderLayout.EAST );

41 panel3.add( new JButton( "Sur" ), BorderLayout.SOUTH );

42 panel3.add( label3, BorderLayout.CENTER );

43 panelPesta~nas.addTab( "Pesta~na Tres", null, panel3, "Tercer Panel" );

44

45 add( panelPesta~nas ); // agregar JTabbedPane a la ventana

46 } // fin del constructor VentanaJTabbedPane

47 } // fin de la clase VentanaJTabbedPane

El constructor, lıneas 15–46, construye la GUI. La lınea 19 crea un JTabbed-Pane vacıo con la configuracion por defecto—esto es, las pestanas en la partesuperior. Si las pestanas no caben en una lınea, estas son acomodadas paraformar lıneas adicionales de pestanas. Despues el constructor crea los panelespanel1, panel2 y panel3 y sus componentes GUI. Conforme se va configu-rando cada panel, se va agregando este al panel de pestanas, usando el metodoaddTab de JTabbedPane con cuatro argumentos. El primer argumento es unacadena que indica el tıtulo de la pestana. El segundo argumento es una refe-rencia tipo Icon que indica la imagen que se muestra en la pestana. Si esta esuna referencia null, no se muestra imagen. El tercer argumento es una refe-rencia Component que representa el componente GUI que se muestra cuandoel usuario pulsa la pestana. El ultimo argumento es una cadena que indica lasugerencia para la pestana. Por ejemplo, la lınea 25 agrega panel1 del tipoJPanel a panelPesta~nas con tıtulo “Pestana Uno” y la sugerencia “PrimerPanel”. Los JPanel panel2 y panel3 son agregados a panelPesta~nas en las

Page 114: notasGUI

114 Componentes GUI

lıneas 32 y 43. Para ver una pestana, pulsar con el raton o usar las teclas denavegacion para ciclar a traves de las pestanas.

1 // DemoJTabbedPane.java

2 // Mostrando JTabbedPane.

3 import javax.swing.JFrame;

4

5 public class DemoJTabbedPane {

6

7 public static void main( String args[] ) {

8

9 VentanaJTabbedPane ventanaPesta~nas = new VentanaJTabbedPane();

10 ventanaPesta~nas.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

11 ventanaPesta~nas.setSize( 250, 200 ); // fijar tama~no de la ventana

12 ventanaPesta~nas.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase DemoJTabbedPane

3.23. Manejador de Diseno: BoxLayout

El manejador de diseno BoxLayout permite que los componentes GUI seanarreglados de izquierda a derecha y de arriba hacia abajo en un contenedor.La clase Box declara un contenedor con BoxLayout como su manejador dediseno y proporciona metodos estaticos para crear un Box con un BoxLayout

horizontal o vertical.La aplicacion siguiente muestra un BoxLayout y la clase contenedora Box

que usa BoxLayout como su manejador de diseno por defecto.

1 // VentanaBoxLayout.java

2 // Demostrando BoxLayout.

3 import java.awt.Dimension;

4 import javax.swing.JFrame;

5 import javax.swing.Box;

6 import javax.swing.JButton;

7 import javax.swing.BoxLayout;

8 import javax.swing.JPanel;

9 import javax.swing.JTabbedPane;

10

11 public class VentanaBoxLayout extends JFrame {

12

13 // configurar GUI

14 public VentanaBoxLayout() {

Page 115: notasGUI

3.23 Manejador de Diseno: BoxLayout 115

15

16 super( "Mostrando BoxLayout" );

17

18 // crear contenedores Box que tienen BoxLayout

19 Box horizontal1 = Box.createHorizontalBox();

20 Box vertical1 = Box.createVerticalBox();

21 Box horizontal2 = Box.createHorizontalBox();

22 Box vertical2 = Box.createVerticalBox();

23

24 final int TAM = 3; // numero de botones en cada BOX

25

26 // agregar botones a horizontal1

27 for ( int cont = 0; cont < TAM; cont++ )

28 horizontal1.add( new JButton( "Boton " + cont ) );

29

30 // crear puntal y agregar botones a vertical1

31 for ( int cont = 0; cont < TAM; cont++ ) {

32

33 vertical1.add( Box.createVerticalStrut( 25 ) );

34 vertical1.add( new JButton( "Boton " + cont ) );

35 } // fin del for

36

37 // crear pegamento horizontal y agregar botones a horizontal2

38 for ( int cont = 0; cont < TAM; cont++ ) {

39

40 horizontal2.add( Box.createHorizontalGlue() );

41 horizontal2.add( new JButton( "Boton " + cont ) );

42 } // fin del for

43

44 // crear area rıgida y agregar botones a vertical2

45 for ( int cont = 0; cont < TAM; cont++ ) {

46

47 vertical2.add( Box.createRigidArea( new Dimension( 12, 8 ) ) );

48 vertical2.add( new JButton( "Boton " + cont ) );

49 } // fin del for

50

51 // crear pegamento vertical y agregar botones al panel.

52 JPanel panel = new JPanel();

53 panel.setLayout( new BoxLayout( panel, BoxLayout.Y_AXIS ) );

54

55 for ( int cont = 0; cont < TAM; cont++ ) {

56

57 panel.add( Box.createGlue() );

58 panel.add( new JButton( "Boton " + cont ) );

59 } // fin del for

Page 116: notasGUI

116 Componentes GUI

60

61 // crear a JTabbedPane

62 JTabbedPane tabs = new JTabbedPane(

63 JTabbedPane.TOP, JTabbedPane.SCROLL_TAB_LAYOUT );

64

65 // colocar cada contenedor en en un panel de pesta~nas.

66 tabs.addTab( "Caja Horizontal", horizontal1 );

67 tabs.addTab( "Caja Vertical con Puntales", vertical1 );

68 tabs.addTab( "Caja Horizontal con Pegamento", horizontal2 );

69 tabs.addTab( "Caja Vertical con Areas Rıgidas", vertical2 );

70 tabs.addTab( "Caja Vertical con Pegamento", panel );

71

72 add( tabs ); // colocar panel de pesta~nas en la ventana

73 } // fin del constructor de la clase VentanaBoxLayout

74 } // fin de clase VentanaBoxLayout

Las lıneas 19–22 crea contenedores Box. Las referencias horizontal1 yhorizontal2 son inicializadas con el metodo estatico createHorizontalBox

de Box, la cual regresa un contenedor Box con un BoxLayout horizontal enel cual los componentes GUI son arreglados de izquierda a derecha. Lasvariables vertical1 y vertical2 son inicializadas con el metodo estaticocreateVerticalBox, el cual regresa referencias a contenedores Box con unBoxLayout vertical en el cual los componentes GUI son arreglados de arribahacia abajo.

La sentencia for en las lıneas 27–28 agregan tres JButton a horizontal1.La sentencia for en las lıneas 31–35 agregan tres JButton a vertical1. Antesde agregar cada boton, la lınea 33 agregra un puntal vertical al contenedorcon el metodo estatico createVerticalStrut de Box. Un puntal vertical esun componente GUI invisible que tiene una altura fija de pıxeles y esta es usa-da para garantizar una cantidad fija de espacio entre los componentes GUI.El argumento entero al metodo createVerticalStrut determina la alturadel puntal en pıxeles. Cuando el contenedor es redimensionado, la distan-cia entre los componentes GUI separados por puntales no cambian. La claseBox tambien declara el metodo createHorizontalStrut para BoxLayout

horizontales.

La sentencia for en las lıneas 38–42 agrega tres JButton a horizontal2.Antes de agregar cada boton, la lınea 40 agrega pegamento horizontal alcontenedor con el metodo estatico createHorizontalGlue de Box. El pega-mento horizontal es un componente invisible que puede ser usado entre com-ponentes GUI de tamano fijo para ocupar espacio adicional. Normalmente,

Page 117: notasGUI

3.23 Manejador de Diseno: BoxLayout 117

espacio extra aparece a la derecha del ultimo componente GUI horizontalo abaja de la ultimo vertical en un BoxLayout. El pegamento permite queel espacio extra sea colocado entre los componentes GUI. Cuando el conte-nedor es redimensionado, los componentes separados por componentes ce-mento permanecen del mismo tamano, pero el cemento se estrecha o contraepara ocupar el espacio entre ellos. La clase Box tambien declara el metodocreateVerticalGlue para BoxLayout verticales.

La sentencia en las lıneas 45–49 agrega tres JButton a vertical2. An-tes de que cada boton sea agregado, la lınea 47 agrega una area rigida alcontenedo con el metodo estatico createRigidArea. Una area rıgida es uncomponente invisible GUI que siempre tiene fijo un ancho y alto. El argu-mento al metodo createRigidArea es un objeto Dimension que indica laaltura y el ancho del area.

Las lıneas 52–53 crean un objeto JPanel y fija su manejador a un BoxLayout

en la forma convencional, usando el metodo setLayout de Container. Elconstructor BoxLayout recibe una referencia al contenedor para el cual con-trola el manejador y una constante indicando si el manejador es horizontalcon BoxLayout.X AXIS, o vertical empleando BoxLayout.Y AXIS.

La sentencia for en las lıneas 55–59 agregan tres JButton al panel. An-tes de agregar cada boton, la lınea 57 agrega un componente pegamento alcontenedor con el metodo estatico createGlue. Este componente se expandeo contrae basado en el tamano de la caja.

Las lıneas 62–63 crea un JTabbedPane para mostrar los cinco contene-dores en este programa. El argumento JTabbedPane.TOP indica en el cons-tructor que las pestanas deberan aparecer en la parte superior. El argumentoJTabbedPane.SCROLL TAB LAYOUT indica que las etiquetas deberan despla-zarse si hay muchas para caber en una lınea.

Los contenedores Box y el JPanel son agregados al JTabbedPane en laslıneas 66–70.

1 // DemoBoxLayout.java

2 // Demostrando BoxLayout.

3 import javax.swing.JFrame;

4

5 public class DemoBoxLayout {

6

7 public static void main( String args[] ) {

8

9 VentanaBoxLayout boxLayoutFrame = new VentanaBoxLayout();

10 boxLayoutFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

Page 118: notasGUI

118 Componentes GUI

11 boxLayoutFrame.setSize( 400, 220 ); // fijar tama~no ventana

12 boxLayoutFrame.setVisible( true ); // mostrar ventana

13 } // fin de main

14 } // fin de la clase DemoBoxLayout

Page 119: notasGUI

Bibliografıa

[1] H. M. Deitel, Java How to Program, Sevent Edition, Prentice Hall, 2007.

[2] J. Friesen, Java SE 6 Platform: From Novice to Professional, Apress,2007.