Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Tema12-GUI Java
Tema12-GUI Java
Fig. 12.2 冷 Programa de suma que utiliza a JOptionPane para entrada y salida (parte 1 de 2).
12 String segundoNumero =
13 JOptionPane.showInputDialog(“Introduzca el segundo entero”);
14
15 // convierte las entradas String en valores int para usarlos en un cálculo
16 int numero1 = Integer.parseInt(primerNumero);
17 int numero2 = Integer.parseInt(segundoNumero);
18
19 int suma = numero1 + numero2;
20
21 // muestra los resultados en un diálogo de mensajes de JOptionPane
22 JOptionPane.showMessageDialog(null, “La suma es “ + suma,
23 “Suma de dos enteros”, JOptionPane.PLAIN_MESSAGE);
24 }
25 } // fin de la clase Suma
(b) Diálogo de entrada mostrado por las líneas 12 y 13 (c) Diálogo de mensaje mostrado por las líneas 22 y 23; Cuando el usuario hace
clic en Aceptar, el diálogo de mensaje se cierra (se quita de la pantalla)
Fig. 12.2 冷 Programa de suma que utiliza a JOptionPane para entrada y salida (parte 2 de 2).
Diálogos de entrada
La línea 3 importa la clase JOptionPane. Las líneas 10 y 11 declaran la variable String primerNumero, y le
asignan el resultado de la llamada al método static showInputDialog de JOptionPane. Este método
muestra un diálogo de entrada (vea la primera captura de pantalla en la figura 12.2(a)), usando el argumen-
to String del método (“Introduzca el primer entero”) como indicador.
El usuario escribe caracteres en el campo de texto y después hace clic en el botón Aceptar u oprime
la tecla Intro para enviar el objeto String al programa. Al hacer clic en Aceptar también se cierra (ocul-
ta) el diálogo. [Nota: si escribe en el campo de texto y no aparece nada, actívelo haciendo clic sobre él
con el ratón]. A diferencia de Scanner, que puede utilizarse para que el usuario introduzca valores de
varios tipos mediante el teclado, un diálogo de entrada sólo puede introducir objetos String. Esto es común
en la mayoría de los componentes de la GUI. El usuario puede escribir cualquier carácter en el campo de
texto del diálogo de entrada. Nuestro programa asume que el usuario introduce un valor entero válido.
Si el usuario hace clic en el botón Cancelar, showInputDialog devuelve null. Si el usuario escribe un
valor no entero o si hace clic en el botón Cancelar en el diálogo de entrada, ocurrirá una excepción y el
programa no operará en forma correcta. Las líneas 12 y 13 muestran otro diálogo de entrada que pide
al usuario que introduzca el segundo entero. Cada diálogo JOptionPane que usted muestre en pantalla
se conoce como diálogo modal. Mientras que el diálogo esté en la pantalla, el usuario no podrá interac-
tuar con el resto de la aplicación.
Diálogos de mensaje
Las líneas 22 y 23 usan el método static showMessageDialog de JOptionPane para mostrar un diálogo
de mensaje (la última captura de pantalla de la figura 12.2) que contiene la suma. El primer argumento
ayuda a la aplicación de Java a determinar en dónde debe colocar el cuadro de diálogo. Por lo general, un
diálogo se muestra desde una aplicación GUI con su propia ventana. El primer argumento se refiere a esa
ventana (la cual se denomina ventana padre) y hace que el diálogo aparezca centrado sobre el padre (como
veremos en la sección 12.9). Si el primer argumento es null, el cuadro de diálogo se muestra en la parte
central de la pantalla. El segundo argumento es el mensaje a mostrar; en este caso, el resultado de concatenar
el objeto String “La suma es “ y el valor de suma. El tercer argumento (“Suma de dos enteros”) repre-
senta el objeto String que debe aparecer en la barra de título del diálogo, en la parte superior. El cuarto
argumento (JOptionPane.PLAIN_MESSAGE) es el tipo de diálogo de mensaje a mostrar. Un diálogo PLAIN_
MESSAGE no muestra un icono a la izquierda del mensaje. La clase JOptionPane proporciona varias versiones
sobrecargadas de los métodos showInputDialog y showMessageDialog, así como métodos que muestran
otros tipos de diálogos. Para obtener la información completa, visite el sitio http://docs.oracle.com/
javase/7/docs/api/javax/swing/JOptionPane.html.
Componente Descripción
Object
Component
Container
JComponent
La clase Component (paquete java.awt) es una superclase que declara las características comunes de
los componentes de GUI en los paquetes java.awt y javax.swing. Cualquier objeto que sea un Container
(paquete java.awt) se puede utilizar para organizar a otros objetos Component, adjuntando esos objetos
Component al objeto Container. Los objetos Container se pueden colocar en otros objetos Container para
organizar una GUI.
La clase JComponent (paquete javax.swing) es una subclase de Container. JComponent es la super-
clase de todos los componentes ligeros de Swing, y declara los atributos y comportamientos comunes.
Debido a que JComponent es una subclase de Container, todos los componentes ligeros de Swing son
también objetos Container. Algunas de las características comunes que soporta JComponent son:
1. Una apariencia visual adaptable, la cual puede utilizarse para personalizar la apariencia de los
componentes (por ejemplo, para usarlos en plataformas específicas). En la sección 22.6 veremos
un ejemplo de esto.
2. Teclas de método abreviado (llamadas nemónicos) para un acceso directo a los componentes de
la GUI por medio del teclado. En la sección 22.4 veremos un ejemplo de esto.
3. Breves descripciones del propósito de un componente de la GUI (lo que se conoce como cuadros
de información sobre herramientas o tool tips) que se muestran cuando el cursor del ratón se coloca
sobre el componente durante un breve periodo. En la siguiente sección veremos un ejemplo de esto.
4. Soporte para accesibilidad, como lectores de pantalla Braille para las personas con impedimentos
visuales.
5. Soporte para la localización de la interfaz de usuario; es decir, personalizar la interfaz de usuario
para mostrarla en distintos lenguajes y utilizar las convenciones de la cultura local.
La aplicación de las figuras 12.6 y 12.7 demuestra varias características de JLabel y presenta la es-
tructura que utilizamos en la mayoría de nuestros ejemplos de GUI. No resaltamos el código en este
ejemplo, ya que casi todo es nuevo. [Nota: hay muchas más características para cada componente de GUI
de las que podemos cubrir en nuestros ejemplos. Para conocer todos los detalles acerca de cada compo-
nente de la GUI, visite su página en la documentación en línea. Para la clase JLabel, visite docs.oracle.
com/javase/7/docs/api/javax/swing/JLabel.html].
19 super(“Prueba de JLabel”);
20 setLayout(new FlowLayout()); // establece el esquema del marco
21
22 // Constructor de JLabel con un argumento String
23 etiqueta1 = new JLabel(“Etiqueta con texto”);
24 etiqueta1.setToolTipText(“Esta es etiqueta1”);
25 add(etiqueta1); // agrega etiqueta1 a JFrame
26
27 // Constructor de JLabel con argumentos de cadena, Icono y alineación
28 Icon insecto = new ImageIcon(getClass().getResource( “insecto1.png”));
29 etiqueta2 = new JLabel(“Etiqueta con texto e icono”, insecto,
30 SwingConstants.LEFT);
31 etiqueta2.setToolTipText(“Esta es etiqueta2”);
32 add(etiqueta2); // agrega etiqueta2 a JFrame
33
34 etiqueta3 = new JLabel(); // constructor de JLabel sin argumentos
35 etiqueta3.setText(“Etiqueta con icono y texto en la parte inferior”);
36 etiqueta3.setIcon(insecto); // agrega icono a JLabel
37 etiqueta3.setHorizontalTextPosition(SwingConstants.CENTER);
38 etiqueta3.setVerticalTextPosition(SwingConstants.BOTTOM);
39 etiqueta3.setToolTipText(“Esta es etiqueta3”);
40 add(etiqueta3); // agrega etiqueta3 a JFrame
41 }
42 } // fin de la clase LabelFrame
La clase LabelFrame (figura 12.6) extiende a JFrame para heredar las características de una ventana.
Utilizaremos una instancia de la clase LabelFrame para mostrar una ventana que contiene tres objetos
JLabel. Las líneas 12 a 14 declaran las tres variables de instancia JLabel, cada una de las cuales se instancia
en el constructor de LabelFrame (líneas 17 a 41). Por lo general, el constructor de la subclase de JFrame
crea la GUI que se muestra en la ventana, cuando se ejecuta la aplicación. La línea 19 invoca al constructor
de la superclase JFrame con el argumento “Prueba de JLabel”. El constructor de JFrame utiliza este ob-
jeto String como el texto en la barra de título de la ventana.
posición vertical en SwingConstants son TOP, CENTER y BOTTOM (figura 12.8). La línea 39 (figura 12.6)
establece el texto de información sobre [herramientas para etiqueta3. La línea 40 agrega etiqueta3 al
objeto JFrame.
Cuando el usuario escribe datos en un objeto JTextField o JPasswordField y después oprime Intro,
ocurre un evento. Nuestro siguiente ejemplo demuestra cómo un programa puede realizar una tarea en
respuesta a ese evento. Las técnicas que se muestran aquí se pueden aplicar a todos los componentes de GUI
que generen eventos.
La aplicación de las figuras 12.9 y 12.10 utiliza las clases JTextField y JPasswordField para crear y
manipular cuatro campos de texto. Cuando el usuario escribe en uno de los campos de texto y después
oprime Intro, la aplicación muestra un cuadro de diálogo de mensaje que contiene el texto que escribió el
usuario. Sólo podemos escribir en el campo de texto que esté “enfocado”. Cuando el usuario hace clic en
ese componente, éste recibe el enfoque. Esto es importante, ya que el campo de texto con el enfoque es el
que genera un evento cuando el usuario oprime Intro. En este ejemplo, cuando el usuario oprime Intro en
el objeto JPasswordField, se revela la contraseña. Empezaremos por explicar la preparación de la GUI, y
después sobre el código para manejar eventos.
36
37 // construye campo de contraseña con texto predeterminado
38 campoContrasenia = new JPasswordField(“Texto oculto”);
39 add(campoContrasenia); // agrega campoContrasenia a JFrame
40
41 // registra los manejadores de eventos
42 ManejadorCampoTexto manejador = new ManejadorCampoTexto();
43 campoTexto1.addActionListener(manejador);
44 campoTexto2.addActionListener(manejador);
45 campoTexto3.addActionListener(manejador);
46 campoContrasenia.addActionListener(manejador);
47 }
48
49 // clase interna privada para el manejo de eventos
50 private class ManejadorCampoTexto implements ActionListener
51 {
52 // procesa los eventos de campo de texto
53 @Override
54 public void actionPerformed(ActionEvent evento)
55 {
56 String cadena = “”;
57
58 // el usuario oprimió Intro en el objeto JTextField campoTexto1
59 if (evento.getSource() == campoTexto1)
60 cadena = String.format(“campoTexto1: %s”,
61 evento.getActionCommand());
62
63 // el usuario oprimió Intro en el objeto JTextField campoTexto2
64 else if (evento.getSource() == campoTexto2)
65 cadena = String.format(“campoTexto2: %s”,
66 evento.getActionCommand() );
67
68 // el usuario oprimió Intro en el objeto JTextField campoTexto3
69 else if (evento.getSource() == campoTexto3)
70 cadena = String.format(“campoTexto3: %s”,
71 evento.getActionCommand());
72
73 // el usuario oprimió Intro en el objeto JTextField campoContrasenia
74 else if (evento.getSource() == campoContrasenia)
75 cadena = String.format(“campoContrasenia: %s”,
76 evento.getActionCommand());
77
78 // muestra el contenido del objeto JTextField
79 JOptionPane.showMessageDialog(null, cadena);
80 }
81 } // fin de la clase interna privada ManejadorCampoTexto
82 } // fin de la clase CampoTextoMarco
La clase CampoTextoMarco extiende a JFrame y declara tres variables JTextField y una variable
JPasswordField (líneas 13 a 16). Cada uno de los correspondientes campos de texto se instancia y se
adjunta al objeto CampoTextoMarco en el constructor (líneas 19 a 47).
Creación de la GUI
La línea 22 establece el esquema del objeto CampoTextoMarco a FlowLayout. La línea 25 crea el objeto
campoTexto1 con 10 columnas de texto. La anchura en píxeles de una columna de texto se determina con
base en la anchura promedio de un carácter en el tipo de letra actual del campo de texto. Cuando el
texto que se muestra es más ancho que el campo de texto en sí, la parte del texto del lado derecho no es
visible. Si usted escribe en un campo de texto y el cursor llega al extremo derecho del campo, el texto en
el extremo izquierdo se empuja hacia el lado izquierdo del campo y ya no estará visible. Los usuarios
pueden usar las flechas de dirección izquierda y derecha para recorrer el texto completo. La línea 26
agrega el objeto campoTexto1 al objeto JFrame.
La línea 29 crea el objeto campoTexto2 con el texto inicial “Escriba el texto aqui” para mostrarlo
en el campo de texto. La anchura del campo se determina con base en la anchura del texto predeterminado
especificado en el constructor. La línea 30 agrega el objeto campoTexto2 al objeto JFrame.
La línea 33 crea el objeto campoTexto3 y llama al constructor de JTextField con dos argumentos:
el texto predeterminado “Campo de texto no editable” para mostrarlo y la anchura del campo de
texto en columnas (21). La línea 34 utiliza el método setEditable (heredado por JTextField de la
clase JTextComponent) para hacer el campo de texto no editable; es decir, el usuario no puede modificar
el texto en el campo. La línea 35 agrega el objeto campoTexto3 al objeto JFrame.
La línea 38 crea campoContrasenia con el texto “Texto oculto” que muestra en el campo de texto.
La anchura de este campo de texto se determina con base en la anchura del texto predeterminado. Al eje-
cutar la aplicación, observe que el texto se muestra como una cadena de asteriscos. La línea 39 agrega cam-
poContrasenia al objeto JFrame.
private. Puesto que los manejadores de eventos tienden a ser específicos para la aplicación en la que
están definidos, a menudo se implementan como clases internas private o como clases internas anóni-
mas (sección 12.11).
Los componentes de GUI pueden generar una variedad de eventos en respuesta a las interacciones del
usuario. Cada evento se representa mediante una clase, y sólo puede procesarse mediante el tipo apropiado
de manejador de eventos. En la mayoría de los casos, los eventos que soporta un componente se describen
en la documentación de la API de Java para la clase de ese componente y sus superclases. Cuando el usuario
oprime Intro en un objeto JTextField o JPasswordField, ocurre un evento ActionEvent (paquete java.
awt.event). Dicho evento se procesa mediante un objeto que implementa la interfaz ActionListener
(paquete java.awt.event). La información aquí descrita está disponible en la documentación de la API
de Java para las clases JTextField y ActionEvent. Como JPasswordField es una subclase de JTextField,
JPasswordField soporta los mismos eventos.
Para prepararnos para manejar los eventos en este ejemplo, la clase interna ManejadorCampoTexto
implementa la interfaz ActionListener y declara el único método en esa interfaz: actionPerformed
(líneas 53 a 80). Este método especifica las tareas a realizar cuando ocurre un evento ActionEvent. Por
lo tanto, la clase ManejadorCampoTexto cumple con el paso 1 que se listó anteriormente en esta sección.
En breve hablaremos sobre los detalles del método actionPerformed.
determinar cuál campo de texto generó el evento cada vez que se hace una llamada a actionPerformed.
El componente con el que interactúa el usuario es el origen del evento. Cuando el usuario oprime Intro
mientras uno de los campos de texto o el campo contraseña tiene el enfoque, el sistema crea un objeto
ActionEvent único que contiene información acerca del evento que acaba de ocurrir, como el origen del
evento y el texto en el campo de texto. Después, el sistema pasa este objeto ActionEvent en una llamada al
método actionPerformed del componente de escucha de eventos. La línea 56 declara el objeto String que
se va a mostrar. La variable se inicializa con la cadena vacía: un objeto String que no contiene caracteres.
En caso de que no se ejecute ninguna de las bifurcaciones de la instrucción if anidada en las líneas 59 a 76,
el compilador requiere que se inicialice la variable.
El método getSource de ActionEvent (que se llama en las líneas 59, 64, 69 y 74) devuelve una refe-
rencia al origen del evento. La condición en la línea 59 pregunta, “¿Es campoTexto1 el origen del evento?”
Esta condición compara las referencias en ambos lados del operador == para determinar si se refieren al
mismo objeto. Si ambos se refieren a campoTexto1, el usuario oprimió Intro en campoTexto1. Después, las
líneas 60 y 61 crean un objeto String que contiene el mensaje que la línea 79 mostrará en un diálogo de
mensaje. La línea 61 utiliza el método getActionCommand de ActionEvent para obtener el texto que escri-
bió el usuario en el campo de texto que generó el evento.
En este ejemplo, mostramos el texto de la contraseña en el objeto JPasswordField cuando el usuario
oprime Intro en ese campo. Algunas veces es necesario procesar mediante programación los caracteres en
una contraseña. El método getPassword de la clase JPasswordField devuelve los caracteres de la contra-
seña como un arreglo de tipo char.
La clase PruebaCampoTexto
La clase PruebaCampoTexto (figura 12.10) contiene el método main que ejecuta esta aplicación y muestra
un objeto de la clase CampoTextoMarco. Al ejecutar la aplicación, incluso el campo JTextField (campo-
Texto3), que no se puede editar, puede generar un evento ActionEvent. Para probar esto, haga clic en el
campo de texto para darle el enfoque y después oprima Intro. Además, el texto actual de la contraseña se
muestra al oprimir Intro en el campo JPasswordField. ¡Desde luego que generalmente no se debe mostrar
la contraseña!
Esta aplicación usó un solo objeto de la clase ManejadorCampoTexto como el componente de escucha
de eventos para cuatro campos de texto. Empezando en la sección 12.10, verá que es posible declarar varios
objetos de escucha de eventos del mismo tipo, y registrar cada objeto para cada evento de un componente
de la GUI por separado. Esta técnica nos permite eliminar la lógica if...else utilizada en el manejador de
eventos de este ejemplo, al proporcionar manejadores de eventos separados para los eventos de cada com-
ponente.
de AWT como de Swing. Los tipos de eventos adicionales que son específicos para los componentes de
GUI de Swing se declaran en el paquete javax.swing.event.
Object ActionEvent
AdjustmentEvent
EventObject
ContainerEvent
ItemEvent
AWTEvent
FocusEvent
TextEvent
PaintEvent
ComponentEvent
WindowEvent
InputEvent
KeyEvent MouseEvent
MouseWheelEvent
Resumiremos las tres partes requeridas para el mecanismo de manejo de eventos que vimos en la sec-
ción 12.6: el origen del evento, el objeto del evento y el componente de escucha del evento. El origen del evento
es el componente específico de la GUI con el que interactúa el usuario. El objeto del evento encapsula in-
formación acerca del evento que ocurrió, como una referencia al origen del mismo, y cualquier información
específica del evento que pueda requerir el componente de escucha del evento, para que pueda manejarlo.
El componente de escucha del evento es un objeto que recibe una notificación del origen del evento cuan-
do éste ocurre; en efecto, “escucha” un evento, y uno de sus métodos se ejecuta en respuesta al evento. Un
método del componente de escucha del evento recibe un objeto evento cuando se notifica al componente
de escucha acerca del evento. Después, el componente de escucha del evento utiliza el objeto evento para
responder. A este modelo de manejo de eventos se le conoce como modelo de eventos por delegación, ya
que el procesamiento de un evento se delega a un objeto específico (el componente de escucha de eventos)
de la aplicación.
Para cada tipo de objeto evento, hay por lo general una interfaz de escucha de eventos que le corres-
ponde. Un componente de escucha de eventos para un evento de GUI es un objeto de una clase que
implementa a una o más de las interfaces de escucha de eventos de los paquetes java.awt.event y
javax.swing.event. Muchos de los tipos de componentes de escucha de eventos son comunes para los
componentes de Swing y de AWT. Dichos tipos se declaran en el paquete java.awt.event, y algunos de
ellos se muestran en la figura 12.12. Los tipos de escucha de eventos adicionales específicos para los
componentes de Swing se declaran en el paquete javax.swing.event.
«interfaz»
java.util.EventListener
«interfaz» «interfaz»
TextListener WindowListener
Fig. 12.12 冷 Algunas interfaces comunes de componentes de escucha de eventos del paquete java.awt.event.
Cada interfaz de escucha de eventos especifica uno o más métodos manejadores de eventos que deben
declararse en la clase que implementa a la interfaz. En la sección 10.9 vimos que cualquier clase que imple-
menta a una interfaz debe declarar a todos los métodos abstract de esa interfaz; en caso contrario, la clase
es abstract y no puede utilizarse para crear objetos.
Cuando ocurre un evento, el componente de la GUI con el que el usuario interactuó notifica a sus
componentes de escucha registrados, llamando al método de manejo de eventos apropiado de cada componente
de escucha. Por ejemplo, cuando el usuario oprime la tecla Intro en un objeto JTextField, se hace una
llamada al método actionPerformed del componente de escucha registrado. En la siguiente sección com-
pletaremos nuestro análisis sobre cómo funciona el manejo de eventos del ejemplo anterior.
Registro de eventos
Todo JComponent tiene una variable de instancia llamada listenerList, que hace referencia a un obje-
to de la clase EventListenerList (paquete javax.swing.event). Cada objeto de una subclase de
JComponent mantiene referencias a todos sus componentes de escucha registrados en listenerList.
Por simplicidad, hemos colocado a listenerList en el diagrama como un arreglo, abajo del objeto
JTextField en la figura 12.13.
campoTexto1 manejador
...
campoTexto1.addActionListener(manejador);
se coloca en el objeto listenerList de campoTexto1 una nueva entrada que contiene una referencia al
objeto ManejadorCampoTexto. Aunque no se muestra en el diagrama, esta nueva entrada también incluye
el tipo del componente de escucha (ActionListener). Mediante el uso de este mecanismo, cada compo-
nente ligero de GUI de Swing mantiene su propia lista de componentes de escucha que se registraron para
manejar los eventos del componente.
las administran los componentes de la GUI por usted. Todo lo que usted necesita hacer es registrar un
manejador de eventos para el tipo de evento específico que requiere su aplicación, y el componente de GUI
asegurará que se llame al método apropiado del manejador de eventos cuando ocurra el evento. Hablaremos
sobre otros tipos de eventos e interfaces de escucha de eventos a medida que se vayan necesitando, con cada
nuevo componente que vayamos introduciendo.
12.9 JButton
Un botón es un componente en el que el usuario hace clic para desencadenar cierta acción. Una aplica-
ción de Java puede utilizar varios tipos de botones, incluyendo botones de comando, casillas de veri-
ficación, botones interruptores y botones de opción. En la figura 12.14 se muestra la jerarquía de
herencia de los botones de Swing que veremos en este capítulo. Como puede ver en el diagrama, todos
los tipos de botones son subclases de AbstractButton (paquete javax.swing), la cual declara las carac-
terísticas comunes para los botones de Swing. En esta sección nos concentraremos en los botones que se
utilizan comúnmente para iniciar un comando.
JComponent
AbstractButton
JButton JToggleButton
JCheckBox JRadioButton
Un botón de comando (vea la salida de la figura 12.16) genera un evento ActionEvent cuando el usua-
rio hace clic en él. Los botones de comando se crean con la clase JButton. El texto en la cara de un objeto
JButton se llama etiqueta del botón.
La aplicación de las figuras 12.15 y 12.16 crea dos objetos JButton y demuestra que estos objetos
tienen soporte para mostrar objetos Icon. El manejo de eventos para los botones se lleva a cabo mediante
una sola instancia de la clase interna ManejadorBoton (figura 12.15, líneas 39 a 48).
suponen que los archivos de imagen están guardados en el mismo directorio que la aplicación. Por lo
general, las imágenes se colocan en el mismo directorio que la aplicación o en un subdirectorio como
images). Estos archivos de imágenes se incluyen en el ejemplo.
En la línea 28 se crea botonJButtonElegante con el texto “Boton elegante” y el icono insecto1.
De manera predeterminada, el texto se muestra a la derecha del icono. En la línea 29 se utiliza el método
setRolloverIcon (heredado de la clase AbstractButton) para especificar la imagen a mostrar en el
objeto JButton cuando el usuario coloque el ratón sobre el botón. En la línea 30 se agrega el JButton
al objeto JFrame.
Los objetos JButton, al igual que los objetos JTextField, generan eventos ActionEvent que pue-
den ser procesados por cualquier objeto ActionListener. En las líneas 33 a 35 se crea un objeto de la
clase interna private ManejadorBoton y se usa addActionListener para registrarlo como el manejador de
eventos para cada objeto JButton. La clase ManejadorBoton (líneas 39 a 48) declara a actionPerformed para
mostrar un cuadro de diálogo de mensaje que contiene la etiqueta del botón que el usuario oprimió.
Para un evento de JButton, el método getActionCommand de ActionEvent devuelve la etiqueta del
objeto JButton.
Cómo acceder a la referencia this en un objeto de una clase de nivel superior desde una clase interna
Cuando ejecute esta aplicación y haga clic en uno de sus botones, observe que el diálogo de mensaje que
aparece está centrado sobre la ventana de la aplicación. Esto ocurre debido a que la llamada al método
showMessageDialog de JOptionPane (líneas 44 y 45) utiliza a MarcoBoton.this, en vez de null como el
primer argumento. Cuando este argumento no es null, representa lo que se denomina el componente de
GUI padre del diálogo de mensaje (en este caso, la ventana de aplicación es el componente padre) y permi-
te centrar el diálogo sobre ese componente, cuando se muestra el diálogo. MarcoBoton.this representa a
la referencia this del objeto de la clase MarcoBoton de nivel superior.
12.10.1 JCheckBox
La aplicación de las figuras 12.17 y 12.18 utilizan dos objetos JCheckBox para seleccionar el estilo de-
seado de letra para el texto a mostrar en un objeto JTextField. Cuando se selecciona, uno aplica un
estilo en negrita y el otro aplica un estilo en cursivas. Si ambos se seleccionan, el estilo del tipo de letra es
negrita y cursiva. Cuando la aplicación se ejecuta por primera vez, ninguno de los objetos JCheckBox está
activado (es decir, ambos son false), por lo que el tipo de letra es de texto plano. La clase PruebaCheckBox
(figura 12.18) contiene el método main que ejecuta esta aplicación.
Una vez creado e inicializado el objeto JTextField (figura 12.17, línea 24), en la línea 25 se utiliza
el método setFont (heredado por JTextField indirectamente de la clase Component) para establecer el
tipo de letra del objeto JTextField con un nuevo objeto de la clase Font (paquete java.awt). El nuevo
objeto Font se inicializa con “Serif” (un nombre de tipo de letra genérico que parecido a Times y se
soporta en todas las plataformas de Java), estilo Font.PLAIN y tamaño de 14 puntos. A continuación, en
las líneas 28 y 29 se crean dos objetos JCheckBox. El objeto String que se pasa al constructor de JCheckBox
es la etiqueta de la casilla de verificación que aparece de manera predeterminada a la derecha del ob-
jeto JCheckBox.
Cuando el usuario hace clic en un objeto JCheckBox, ocurre un evento ItemEvent. Este evento
puede manejarse mediante un objeto ItemListener, que debe implementar al método itemStateChanged.
En este ejemplo, el manejo de eventos se lleva a cabo mediante una instancia de la clase interna private
ManejadorCheckBox (o ManejadorCasillaVerificacion) (líneas 40 a 60). En las líneas 34 a 36 se crea
una instancia de la clase ManejadorCheckBox y se registra con el método addItemListener como com-
ponente de escucha para ambos objetos JCheckBox.
El método itemStateChanged (líneas 43 a 59) de ManejadorCheckBox es llamado cuando el usuario
hace clic en el objeto negritaJCheckBox o cursivaJCheckBox. En este ejemplo, no necesitamos saber en
cuál de los dos objetos JCheckBox se hizo clic, ya que usamos ambos estados para determinar el tipo de
letra a mostrar. En la línea 49 se utiliza el método isSelected de JCheckBox para determinar si ambos
objetos JCheckBox están seleccionados. De ser así, la línea 50 crea un tipo de letra en negrita y cursiva,
sumando las constantes Font.BOLD y Font.ITALIC para el argumento de estilo de letra del constructor de
Font. La línea 51 determina si la casilla negritaJCheckBox está seleccionada, y de ser así en la línea 52 se
crea un tipo de letra en negrita. La línea 53 determina si está seleccionada la casilla cursivaJCheckBox, y
de ser así en la línea 54 se crea un tipo de letra en cursiva. Si ninguna de las condiciones anteriores es ver-
dadera, en la línea 56 se crea un tipo de letra simple usando la constante Font.PLAIN de Font. Por último,
en la línea 58 se establece el nuevo tipo de letra de campoTexto, el cual cambia el tipo de letra en el objeto
JTextField en pantalla.
12.10.2 JRadioButton
Los botones de opción (que se declaran con la clase JRadioButton) son similares a las casillas de verifica-
ción, en cuanto a que tienen dos estados: seleccionado y no seleccionado (al que también se le conoce como
deseleccionado). Sin embargo, los botones de opción por lo general aparecen como un grupo, en el cual sólo
un botón de opción puede estar seleccionado en un momento dado (vea la salida de la figura 12.20). Los
botones de opción se utilizan para representar opciones mutuamente excluyentes (es decir, en un grupo
no pueden seleccionarse varias opciones al mismo tiempo). La relación lógica entre los botones de opción
se mantiene mediante un objeto ButtonGroup (paquete javax.swing), el cual en sí no es un componente
de la GUI. Un objeto ButtonGroup organiza un grupo de botones y no se muestra a sí mismo en una inter-
faz de usuario. En vez de ello, se muestra en la GUI cada uno de los objetos JRadioButton del grupo.
La aplicación de las figuras 12.19 y 12.20 es similar a la de las figuras 12.17 y 12.18. El usuario puede
alterar el estilo de letra de un objeto JTextField. La aplicación utiliza botones de opción que permiten que
se seleccione solamente un estilo de letra en el grupo a la vez. La clase PruebaBotonOpcion (figura 12.20)
contiene el método main que ejecuta esta aplicación.
Fig. 12.19 冷 Creación de botones de opción, usando ButtonGroup y JRadioButton (parte 1 de 2).
Fig. 12.19 冷 Creación de botones de opción, usando ButtonGroup y JRadioButton (parte 2 de 2).
En las líneas 35 a 42 del constructor (figura 12.19) se crean cuatro objetos JRadioButton y se agre-
gan al objeto JFrame. Cada objeto JRadioButton se crea con una llamada al constructor como la de la
línea 35. Este constructor especifica la etiqueta que aparece de manera predeterminada a la derecha del
objeto JRadioButton, junto con su estado inicial. Un segundo argumento true indica que el objeto
JRadioButton debe aparecer seleccionado al mostrarlo en pantalla.
En la línea 45 se instancia un objeto ButtonGroup llamado grupoOpciones. Este objeto es el “pega-
mento” que forma la relación lógica entre los cuatro objetos JRadioButton y permite que se seleccione
solamente uno de los cuatro en un momento dado. Es posible que no se seleccione ningún JRadioButton
en un ButtonGroup, pero esto sólo puede ocurrir si no se agregan objetos JRadioButton preseleccionados
al objeto ButtonGroup, y si el usuario no ha seleccionado todavía un objeto JRadioButton. En las líneas
46 a 49 se utiliza el método add de ButtonGroup para asociar cada uno de los objetos JRadioButton con
grupoOpciones. Si se agrega al grupo más de un objeto JRadioButton seleccionado, el primer objeto
seleccionado que se agregue será el que quede seleccionado cuando se muestre la GUI en pantalla.
Los objetos JRadioButton, al igual que los objetos JCheckbox, generan eventos tipo ItemEvent
cuando se hace clic sobre ellos. En las líneas 59 a 66 se crean cuatro instancias de la clase interna Manejador-
BotonOpcion (declarada en las líneas 70 a 85). En este ejemplo, cada objeto componente de escucha de
eventos se registra para manejar el evento ItemEvent que se genera cuando el usuario hace clic en cual-
quiera de los objetos JRadioButton. Observe que cada objeto ManejadorBotonOpcion se inicializa con
un objeto Font específico (creado en las líneas 52 a 55).
La clase ManejadorBotonOpcion (línea 70 a 85) implementa la interfaz ItemListener para poder
manejar los eventos ItemEvent generados por los objetos JRadioButton. El constructor almacena el obje-
to Font que recibe como un argumento en la variable de instancia tipoLetra (declarada en la línea 72).
Cuando el usuario hace clic en un objeto JRadioButton, grupoOpciones desactiva el objeto JRadioButton
previamente seleccionado y el método itemStateChanged (líneas 80 a 84) establece el tipo de letra en el
objeto JTextField al tipo de letra almacenado en el objeto componente de escucha de eventos correspon-
diente al objeto JRadioButton. Observe que la línea 82 de la clase interna ManejadorBotonOpcion utiliza
la variable de instancia campoTexto de la clase de nivel superior para establecer el tipo de letra.
cual extiende a la clase JComponent. Ésta es una clase genérica, como la clase ArrayList (capítulo 7). Al
crear un objeto JComboBox hay que especificar el tipo de los objetos que maneja; después el JComboBox
muestra una representación String de cada objeto.
Fig. 12.21 冷 Objeto JComboBox que muestra una lista de nombres de imágenes (parte 1 de 2).
Fig. 12.21 冷 Objeto JComboBox que muestra una lista de nombres de imágenes (parte 2 de 2).
Los objetos JComboBox generan eventos ItemEvent, al igual que los objetos JCheckBox y JRadio-
Button. Este ejemplo también demuestra una forma especial de clase interna, que se utiliza con frecuen-
cia en el manejo de eventos. La aplicación (figuras 12.21 y 12.22) utiliza un objeto JComboBox para
proporcionar una lista de cuatro nombres de archivos de imágenes, de los cuales el usuario puede selec-
cionar una imagen para mostrarla en pantalla. Cuando el usuario selecciona un nombre, la aplicación
muestra la imagen correspondiente como un objeto Icon en un objeto JLabel. La clase PruebaCuadro-
Combinado (figura 12.22) contiene el método main que ejecuta esta aplicación. Las capturas de pantalla
para esta aplicación muestran la lista JComboBox después de hacer una selección, para ilustrar cuál nom-
bre de archivo de imagen fue seleccionado.
En las líneas 19 a 23 (figura 12.21) se declara e inicializa el arreglo iconos con cuatro nuevos objetos
ImageIcon. El arreglo String llamado nombres (líneas 17 y 18) contiene los nombres de los cuatro archivos
de imagen que se guardan en el mismo directorio que la aplicación.
En la línea 31, el constructor inicializa un objeto JComboBox utilizando los objetos String en el arreglo
nombres como los elementos en la lista. Cada elemento de la lista tiene un índice. El primer elemento se
agrega en el índice 0; el siguiente elemento se agrega en el índice 1, y así sucesivamente. El primer elemen-
to que se agrega a un objeto JComboBox aparece como el elemento actualmente seleccionado al mostrar el
objeto JComboBox. Los otros elementos se seleccionan haciendo clic en el objeto JComboBox, y después se-
leccionando un elemento de la lista que aparece.
En la línea 32 se utiliza el método setMaximumRowCount de JComboBox para establecer el máximo
número de elementos a mostrar cuando el usuario haga clic en el objeto JComboBox. Si hay elementos adi-
cionales, el objeto JComboBox proporciona una barra de desplazamiento (vea la primera captura de pan-
talla) que permite al usuario desplazarse por todos los elementos en la lista. El usuario puede hacer clic en
las flechas de desplazamiento que están en las partes superior e inferior de la barra de desplazamiento para
avanzar hacia arriba y hacia abajo de la lista, un elemento a la vez, o puede arrastrar hacia arriba y hacia
abajo el cuadro de desplazamiento que está en medio de la barra de desplazamiento. Para arrastrar
el cuadro de desplazamiento, posicione el ratón sobre éste, mantenga presionado el botón izquierdo y
mueva el ratón. En este ejemplo, la lista desplegable es demasiado corta como para poder arrastrar el cuadro
de desplazamiento, por lo que puede hacer clic en las flechas arriba y abajo o usar la rueda de su ratón
para desplazarse por los cuatro elementos en la lista. La línea 49 adjunta el objeto JComboBox al esquema
FlowLayout de MarcoCuadroCombinado (que se establece en la línea 29). La línea 50 crea el objeto JLabel que
muestra objetos ImageIcon y lo inicializa con el primer objeto ImageIcon en el arreglo iconos. La línea 51
adjunta el objeto JLabel al esquema FlowLayout de MarcoCuadroCombinado.
objeto como argumento para addItemListener. La sintaxis ItemListener() después de new empieza la
declaración de una clase interna anónima que implementa a la interfaz ItemListener. Esto es similar a
empezar una declaración con
La llave izquierda de apertura en la línea 36 y la llave derecha de cierre en la línea 46 delimitan el cuer-
po de la clase interna anónima. Las líneas 38 a 45 declaran el método itemStateChanged de ItemListener.
Cuando el usuario hace una selección de imagenesJComboBox, este método establece el objeto Icon
de etiqueta. El objeto Icon se selecciona del arreglo iconos, determinando el índice del elemento selec-
cionado en el objeto JComboBox con el método getSelectedIndex en la línea 44. Para cada elemento se-
leccionado de un JComboBox, primero se deselecciona otro elemento; por lo tanto, ocurren dos eventos tipo
ItemEvent cuando se selecciona un elemento. Deseamos mostrar sólo el icono para el elemento que
el usuario acaba de seleccionar. Por esta razón, la línea 42 determina si el método getStateChange de
ItemEvent devuelve ItemEvent.SELECTED. De ser así, las líneas 43 y 44 establecen el icono de etiqueta.
La sintaxis que se muestra en las líneas 35 a 46 para crear un manejador de eventos con una clase in-
terna anónima es similar al código que genera un entorno de desarrollo integrado (IDE) de Java. Por lo
general, un IDE permite al programador diseñar una GUI en forma visual, y después el IDE genera código
que implementa a la GUI. El programador sólo inserta instrucciones en los métodos manejadores de even-
tos que declaran cómo manejar cada evento.
12.12 JList
Una lista muestra una serie de elementos, de la cual el usuario puede seleccionar uno o más elementos (vea
la salida de la figura 12.24). Las listas se crean con la clase JList, que extiende directamente a la clase
JComponent. La clase JList (que, al igual que JComboBox, es una clase genérica) soporta listas de selec-
ción simple (que permiten seleccionar solamente un elemento a la vez) y listas de selección múltiple
(que permiten seleccionar cualquier número de elementos a la vez). En esta sección hablaremos sobre las
listas de selección simple.
La aplicación de las figuras 12.23 y 12.24 crea un objeto JList que contiene los nombres de 13 colo-
res. Al hacer clic en el nombre de un color en el objeto JList, ocurre un evento ListSelectionEvent y la
aplicación cambia el color de fondo de la ventana de aplicación al color seleccionado. La clase PruebaLista
(figura 12.24) contiene el método main que ejecuta esta aplicación.
Fig. 12.23 冷 Objeto JList que muestra una lista de colores (parte 1 de 2).
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 MarcoLista extends JFrame
13 {
14 private final JList<String> listaJListColores; // lista para mostrar colores
15 private static final String[] nombresColores = {“Negro”, “Azul”, “Cyan”,
16 “Gris oscuro”, “Gris”, “Verde”, “Gris claro”, “Magenta”,
17 “Naranja”, “Rosa”, “Rojo”, “Blanco”, “Amarillo”};
18 private static final Color[] colores = {Color.BLACK, Color.BLUE,
19 Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN,
20 Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK,
21 Color.RED, Color.WHITE, Color.YELLOW};
22
23 // El constructor de MarcoLista agrega a JFrame el JScrollPane que contiene a
JList
24 public MarcoLista()
25 {
26 super(“Prueba de JList”);
27 setLayout(new FlowLayout());
28
29 listaJListColores = new JList<String>(nombresColores); // lista de
nombresColores
30 listaJListColores.setVisibleRowCount(5); // muestra cinco filas a la vez
31
32 // no permite selecciones múltiples
33 listaJListColores.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
34
35 // agrega al marco un objeto JScrollPane que contiene a JList
36 add(new JScrollPane(listaJListColores));
37
38 listaJListColores.addListSelectionListener(
39 new ListSelectionListener() // clase interna anónima
40 {
41 // maneja los eventos de selección de la lista
42 @Override
43 public void valueChanged(ListSelectionEvent evento)
44 {
45 getContentPane().setBackground(
46 colores[listaJListColores.getSelectedIndex()]);
47 }
48 }
49 );
50 }
51 } // fin de la clase MarcoLista
Fig. 12.23 冷 Objeto JList que muestra una lista de colores (parte 2 de 2).
La línea 29 (figura 12.23) crea el objeto listaJListColores llamado JList. El argumento para el
constructor de JList es el arreglo de objetos Object (en este caso, objetos String) a mostrar en la lista.
La línea 30 utiliza el método setVisibleRowCount de JList para determinar el número de elementos vi-
sibles en la lista.
La línea 33 utiliza el método setSelectionMode de JList para especificar el modo de selección de
la lista. La clase ListSelectionModel (del paquete javax.swing) declara tres constantes que especifican
el modo de selección de un objeto JList: SINGLE_SELECTION (que sólo permite seleccionar un elemen-
to a la vez), SINGLE_INTERVAL_SELECTION (para una lista de selección múltiple que permite seleccionar
varios elementos contiguos) y MULTIPLE_INTERVAL_SELECTION (para una lista de selección múltiple que
no restringe los elementos que se pueden seleccionar).
A diferencia de un objeto JComboBox, un objeto JList no proporciona una barra de desplazamiento si
hay más elementos en la lista que el número de filas visibles. En este caso se utiliza un objeto JScrollPane
para proporcionar la capacidad de desplazamiento. En la línea 36 se agrega una nueva instancia de la
clase JScrollPane al objeto JFrame. El constructor de JScrollPane recibe como argumento el objeto
JComponent que necesita funcionalidad de desplazamiento (en este caso, listaJListColores). Observe
en las capturas de pantalla que aparece una barra de desplazamiento creada por el objeto JScrollPane en el
lado derecho del objeto JList. De manera predeterminada, la barra de desplazamiento sólo aparece cuan-
do el número de elementos en el objeto JList excede al número de elementos visibles.
Las líneas 38 a 49 usan el método addListSelectionListener de JList para registrar un objeto
que implementa a ListSelectionListener (paquete javax.swing.event) como el componente de
escucha para los eventos de selección de JList. Una vez más, utilizamos una instancia de una clase in-
terna anónima (líneas 39 a 48) como el componente de escucha. En este ejemplo, cuando el usuario
realiza una selección de listaJListColores, el método valueChanged (línea 42 a 47) debería cambiar
el color de fondo del objeto MarcoLista al color seleccionado. Esto se logra en las líneas 45 y 46. Obser-
ve el uso del método getContentPane de JFrame en la línea 45. Cada objeto JFrame en realidad consis-
te de tres niveles: el fondo, el panel de contenido y el panel de vidrio. El panel de contenido aparece enfrente
del fondo, y es en donde se muestran los componentes de la GUI en el objeto JFrame. El panel de vidrio
se utiliza para mostrar cuadros de información sobre herramientas y otros elementos que deben aparecer
enfrente de los componentes de la GUI en la pantalla. El panel de contenido oculta por completo el
fondo del objeto JFrame; por ende, para cambiar el color de fondo detrás de los componentes de la GUI,
debe cambiar el color de fondo del panel de contenido. El método getContentPane devuelve una
referencia al panel de contenido del objeto JFrame (un objeto de la clase Container). En la línea 45,
usamos esa referencia para llamar al método setBackground, el cual establece el color de fondo del panel
de contenido a un elemento en el arreglo colores. El color se selecciona del arreglo mediante el uso del
índice del elemento seleccionado. El método getSelectedItem de JList devuelve el índice del elemen-
to seleccionado. Al igual que con los arreglos y los objetos JComboBox, los índices en los objetos JList
están basados en cero.
Fig. 12.25 冷 Objeto JList que permite selecciones múltiples (parte 1 de 2).
Fig. 12.25 冷 Objeto JList que permite selecciones múltiples (parte 2 de 2).
Cada uno de los métodos manejadores de eventos de ratón recibe un objeto MouseEvent como su ar-
gumento, el cual contiene información acerca del evento de ratón que ocurrió, incluyendo las coordenadas
x y y de su ubicación. Estas coordenadas se miden desde la esquina superior izquierda del componente de la
GUI en el que ocurrió el evento. Las coordenadas x empiezan en 0 y se incrementan de izquierda a derecha.
Las coordenadas y empiezan en 0 y se incrementan de arriba hacia abajo. Los métodos y constantes de la
clase InputEvent (superclase de MouseEvent) permiten a una aplicación determinar cuál fue el botón del
ratón que oprimió el usuario.
Es llamado cuando se oprime un botón del ratón, mientras el cursor del ratón está sobre un componente.
Es llamado cuando se oprime y suelta un botón del ratón, mientras el cursor del ratón permanece esta-
cionario sobre un componente. Este evento siempre va precedido por una llamada a mousePressed y
mouseReleased.
Es llamado cuando se suelta un botón de ratón después de ser oprimido. Este evento siempre va precedido
por una llamada a mousePressed y por una o más llamadas a mouseDragged.
Es llamado cuando el botón del ratón se oprime mientras el cursor del ratón se encuentra sobre un com-
ponente y el ratón se mueve mientras el botón sigue oprimido. Este evento siempre va precedido por una
llamada a mousePressed. Todos los eventos de arrastre del ratón se envían al componente en el cual em-
pezó la acción de arrastre.
Es llamado al moverse el ratón (sin oprimir los botones del ratón) cuando su cursor se encuentra sobre un
componente. Todos los eventos de movimiento se envían al componente sobre el cual se encuentra el ratón
posicionado en ese momento.
Java también cuenta con la interfaz MouseWheelListener para permitir a las aplicaciones responder a
la rotación de la rueda de un ratón. Esta interfaz declara el método mouseWheelMoved, el cual recibe un
evento MouseWheelEvent como argumento. La clase MouseWheelEvent (una subclase de MouseEvent)
contiene métodos que permiten al manejador de eventos obtener información acerca de la cantidad de
rotación de la rueda.
89
90 // maneja evento cuando el usuario mueve el ratón
91 @Override
92 public void mouseMoved(MouseEvent evento)
93 {
94 barraEstado.setText(String.format(“Se movio en [%d, %d]”,
95 evento.getX(), evento.getY()));
96 }
97 } // fin de la clase interna ManejadorRaton
98 } // fin de la clase MarcoRastreadorRaton
La línea 23 crea el objeto JPanel llamado panelRaton. Los eventos de ratón de este objeto JPanel
serán rastreados por la aplicación. En la línea 24 se establece el color de fondo de panelRaton en blanco.
Cuando el usuario mueva el ratón hacia el panelRaton, la aplicación cambiará el color de fondo de
panelRaton a verde. Cuando el usuario mueva el ratón hacia fuera del panelRaton, la aplicación cambia-
rá el color de fondo de nuevo a blanco. En la línea 25 se adjunta el objeto panelRaton al objeto JFrame.
Como vimos, por lo general debemos especificar el esquema de los componentes de GUI en un objeto
JFrame. En esa sección presentamos el administrador de esquemas FlowLayout. Aquí utilizamos el es-
quema predeterminado del panel de contenido de un objeto JFrame, BorderLayout, el cual ordena los
componentes en cinco regiones: NORTH, SOUTH, EAST, WEST y CENTER. NORTH corresponde a la parte supe-
rior del contenedor. Este ejemplo utiliza las regiones CENTER y SOUTH. En la línea 25 se utiliza una versión
con dos argumentos del método add para colocar a panelRaton en la región CENTER. El esquema
BorderLayout ajusta automáticamente el tamaño del componente en la región CENTER para utilizar todo
el espacio en el objeto JFrame que no esté ocupado por los componentes de otras regiones. En la sección
12.18.2 hablaremos con más detalle sobre BorderLayout.
En las líneas 27 y 28 del constructor se declara el objeto JLabel llamado barraEstado y se adjunta a
la región SOUTH del objeto JFrame. Este objeto JLabel ocupa la anchura del objeto JFrame. La altura de la
región se determina con base en el objeto Jlabel.
En la línea 31 se crea una instancia de la clase interna ManejadorRaton (líneas 36 a 97) llamada
manejador, la cual responde a los eventos de ratón. En las líneas 32 y 33 se registra manejador como el
componente de escucha para los eventos de ratón de panelRaton. Los métodos addMouseListener y
addMouseMotionListener se heredan indirectamente de la clase Component, y pueden utilizarse para
registrar objetos MouseListener y MouseMotionListener, respectivamente. Un objeto ManejadorRaton
es un MouseListener y es un MotionListener ya que la clase implementa ambas interfaces. Optamos por
implementar ambas interfaces aquí para demostrar una clase que implementa más de una interfaz, pero
también pudimos haber implementado la interfaz MouseInputListener en su lugar.
Cuando el ratón entra y sale del área de panelRaton, se hacen llamadas a los métodos mouseEntered
(líneas 65 a 71) y mouseExited (líneas 74 a 79), respectivamente. El método mouseEntered muestra un
mensaje en el objeto barraEstado, indicando que el ratón entró al objeto JPanel y cambia el color de
fondo a verde. El método mouseExited muestra un mensaje en el objeto barraEstado, indicando que
el ratón está fuera del objeto JPanel (vea la primera ventana de resultados) y cambia el color de fondo a
blanco.
Los otros cinco eventos muestran una cadena en el objeto barraEstado, la cual contiene el evento y
las coordenadas en las que ocurrió. Los métodos getX y getY de MouseEvent devuelven las coordenadas x
y y del ratón, respectivamente, en el momento en el que ocurrió el evento.
ComponentAdapter ComponentListener
ContainerAdapter ContainerListener
FocusAdapter FocusListener
KeyAdapter KeyListener
MouseAdapter MouseListener
MouseMotionAdapter MouseMotionListener
WindowAdapter WindowListener
Fig. 12.30 冷 Las clases adaptadoras de eventos y las interfaces que implementan.
Extensión de MouseAdapter
La aplicación de las figuras 12.31 y 12.32 demuestra cómo determinar el número de clics del ratón
(es decir, la cuenta de clics) y cómo diferenciar los distintos botones del ratón. El componente de escucha
de eventos en esta aplicación es un objeto de la clase interna ManejadorClicRaton (figura 12.31, líneas
25 a 46) que extiende a MouseAdapter, por lo que podemos declarar sólo el método mouseClicked que
necesitamos en este ejemplo.
Fig. 12.31 冷 Demostración de los clics del ratón y cómo diferenciar los botones del mismo (parte 1 de 2).
Fig. 12.31 冷 Demostración de los clics del ratón y cómo diferenciar los botones del mismo (parte 2 de 2).
Un usuario de una aplicación en Java puede estar en un sistema con un ratón de uno, dos o tres
botones. Java cuenta con un mecanismo para diferenciar cada uno de los botones del ratón. La clase
MouseEvent hereda varios métodos de la clase InputEvent que pueden diferenciar los botones de un
ratón con varios botones, o pueden imitarlo con una combinación de teclas y el clic de un botón
del ratón. La figura 12.33 muestra los métodos de InputEvent que se utilizan para diferenciar los clics de
los botones del ratón. Java asume que cada ratón contiene un botón izquierdo. Por ende, es fácil probar
un clic del botón izquierdo del ratón. Sin embargo, los usuarios que tengan un ratón de uno o dos bo-
tones deben usar al mismo tiempo una combinación de teclas y clics del ratón, para simular los botones
que éste no tiene. En el caso de un ratón con uno o dos botones, una aplicación de Java asume que se
hizo clic en el botón central del ratón, si el usuario mantiene oprimida la tecla Alt y hace clic en el botón
izquierdo en un ratón con dos botones, o en el único botón en un ratón con un botón. En el caso de un
ratón con un botón, una aplicación de Java asume que se hizo clic en el botón derecho si el usuario
mantiene oprimida la tecla Meta (algunas veces conocida como la tecla de Comando, o la tecla de la
“Manzana” en la Mac) y hace clic en el botón del ratón.
isMetaDown() Devuelve true cuando el usuario hace clic en el botón derecho del ratón, en un
ratón con dos o tres botones. Para simular un clic con el botón derecho del ratón
en un ratón con un botón, el usuario puede mantener oprimida la tecla Meta en el
teclado y hacer clic con el botón del ratón.
isAltDown() Devuelve true cuando el usuario hace clic con el botón central del ratón, en un
ratón con tres botones. Para simular un clic con el botón central del ratón
en un ratón con uno o dos botones, el usuario puede oprimir la tecla Alt en
el teclado y hacer clic en el único botón o en el botón izquierdo del ratón, respec-
tivamente.
Fig. 12.33 冷 Métodos de InputEvent que ayudan a determinar si se hizo clic con el botón derecho o central del
ratón.
Método paintComponent
Los componentes ligeros de Swing que extienden a la clase JComponent (como JPanel) contienen el
método paintComponent, el cual se llama cuando se muestra un componente ligero de Swing. Al sobres-
cribir este método, puede especificar cómo dibujar figuras usando las herramientas de gráficos de Java.
Al personalizar un objeto JPanel para usarlo como un área dedicada de dibujo, la subclase debe sobres-
cribir el método paintComponent y llamar a la versión de paintComponent de la superclase como la
primera instrucción en el cuerpo del método sobrescrito, para asegurar que el componente se muestre
en forma correcta. La razón de ello es que las subclases de JComponent soportan la transparencia. Para
mostrar un componente en forma correcta, el programa debe determinar si el componente es transpa-
rente. El código que determina esto se encuentra en la implementación del método paintComponent de
la superclase JComponent. Cuando un componente es transparente, paintComponent no borra su fondo
cuando el programa muestra el componente. Cuando un componente es opaco, paintComponent borra
el fondo del componente antes de mostrarlo. La transparencia de un componente ligero de Swing puede
establecerse con el método setOpaque (un argumento false indica que el componente es transparente).
Fig. 12.34 冷 Clase adaptadora que se usa para implementar los manejadores de eventos (parte 1 de 2).
6 import java.awt.event.MouseMotionAdapter;
7 import java.util.ArrayList;
8 import javax.swing.JPanel;
9
10 public class PanelDibujo extends JPanel
11 {
12 // lista de referencias Point
13 private final ArrayList<Point> puntos = new ArrayList<>();
14
15 // establece la GUI y registra el manejador de eventos del ratón
16 public PanelDibujo()
17 {
18 // maneja evento de movimiento del ratón en el marco
19 addMouseMotionListener(
20 new MouseMotionAdapter() // clase interna anónima
21 {
22 // almacena las coordenadas de arrastre y vuelve a dibujar
23 @Override
24 public void mouseDragged(MouseEvent evento)
25 {
26 puntos.add(evento.getPoint());
27 repaint(); // vuelve a dibujar JFrame
28 }
29 }
30 );
31 }
32
33 // dibuja óvalos en un cuadro delimitador de 4 x 4, en las ubicaciones
especificadas en la ventana
34 @Override
35 public void paintComponent(Graphics g)
36 {
37 super.paintComponent(g); // borra el área de dibujo
38
39 // dibuja todos los puntos
40 for (Point punto : puntos)
41 g.fillOval(punto.x, punto.y, 4, 4);
42 }
43 } // fin de la clase PanelDibujo
Fig. 12.34 冷 Clase adaptadora que se usa para implementar los manejadores de eventos (parte 2 de 2).
La clase PanelDibujo (figura 12.34) extiende a JPanel para crear el área dedicada de dibujo. La clase
Point (paquete java.awt) representa una coordenada x-y. Utilizamos objetos de esta clase para almacenar
las coordenadas de cada evento de arrastre del ratón. La clase Graphics se utiliza para dibujar. En este
ejemplo, utilizamos un objeto ArrayList de objetos Point (línea 13) para almacenar la ubicación en la cual
ocurre cada evento de arrastre del ratón. Como veremos más adelante, el método paintComponent utiliza
estos objetos Point para dibujar.
Las líneas 19 a 30 registran un objeto MouseMotionListener para que escuche los eventos de movi-
miento del ratón de PaintPanel. Las líneas 20 a 29 crean un objeto de una clase interna anónima que
extiende a la clase adaptadora MouseMotionAdapter. Recuerde que MouseMotionAdapter implementa
a MouseMotionListener, por lo que el objeto de la clase interna anónima es un MouseMotionListener.
La clase interna anónima hereda una implementación predeterminada de los métodos mouseMoved y
mouseDragged, por lo que de antemano implementa a todos los métodos de la interfaz. Sin embargo, las
implementaciones predeterminadas no hacen nada cuando se les llama. Por lo tanto, sobrescribimos
el método mouseDragged en las líneas 23 a 28 para capturar las coordenadas de un evento de arrastre del
ratón y las almacenamos como un objeto Point. La línea 26 invoca el método getPoint de MouseEvent
para obtener el objeto Point en donde ocurrió el evento, y lo almacena en el objeto ArrayList. La línea 27
llama al método repaint (heredado directamente de la clase Component) para indicar que el objeto Panel-
Dibujo debe actualizarse en la pantalla lo más pronto posible, con una llamada al método paintComponent
de PaintPanel.
El método paintComponent (líneas 34 a 42), que recibe un parámetro Graphics, se llama de manera
automática cada vez que el objeto PaintPanel necesita mostrarse en la pantalla (como cuando se muestra
por primera vez la GUI) o actualizarse en la pantalla (como cuando se hace una llamada al método repaint,
o cuando otra ventana en la pantalla oculta el componente de la GUI y después se vuelve otra vez visible).
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 MarcoDemoTeclas extends JFrame implements KeyListener
10 {
11 private String linea1 = “”; // primera línea del área de texto
12 private String linea2 = “”; // segunda línea del área de texto
13 private String linea3 = “”; // tercera línea del área de texto
14 private JTextArea areaTexto; // área de texto para mostrar la salida
15
16 // constructor de MarcoDemoTeclas
17 public MarcoDemoTeclas()
18 {
19 super(“Demostracion de los eventos de pulsacion de teclas”);
20
21 areaTexto = new JTextArea(10, 15); // establece el objeto JTextArea
22 areaTexto.setText(“Oprima cualquier tecla en el teclado...”);
23 areaTexto.setEnabled(false);
24 areaTexto.setDisabledTextColor(Color.BLACK);
25 add(areaTexto); // agrega el área de texto a JFrame
26
27 addKeyListener(this); // permite al marco procesar los eventos de teclas
28 }
29
30 // maneja el evento de oprimir cualquier tecla
31 @Override
32 public void keyPressed(KeyEvent evento)
33 {
34 linea1 = String.format(“Tecla oprimida: %s”,
35 KeyEvent.getKeyText(evento.getKeyCode())); // muestra la tecla oprimida
36 establecerLineas2y3(evento); // establece las líneas de salida dos y tres
37 }
38
39 // maneja el evento de liberar cualquier tecla
40 @Override
41 public void keyReleased(KeyEvent evento)
42 {
43 linea1 = String.format(“Tecla liberada: %s”,
44 KeyEvent.getKeyText(evento.getKeyCode())); // muestra la tecla liberada
45 establecerLineas2y3(evento); // establece las líneas de salida dos y tres
46 }
47
48 // maneja el evento de oprimir una tecla de acción
49 @Override
50 public void keyTyped(KeyEvent evento)
51 {
52 linea1 = String.format(“Tecla oprimida: %s”, evento.getKeyChar());
53 establecerLineas2y3(evento); // establece las líneas de salida dos y tres
54 }
55
En la línea 25, el constructor agrega el objeto JTextArea llamado areaTexto (en donde se muestra la
salida de la aplicación) al objeto JFrame. Un objeto JTextArea es un área multilínea en la que podemos
mostrar texto (hablaremos sobre los objetos JTextArea con más detalle en la sección 12.20). Observe en
las capturas de pantalla que el objeto areaTexto ocupa toda la ventana. Esto se debe al esquema predeter-
minado BorderLayout del objeto JFrame (que describiremos en la sección 12.18.2 y demostraremos en la
figura 12.41). Cuando se agrega un objeto Component individual a un objeto BorderLayout, el objeto
Component ocupa todo el objeto Container. La línea 23 deshabilita el objeto JTextArea para que el usuario
no pueda escribir en él. Esto hace que el objeto JTextArea se torne de color gris. En la línea 24 se utiliza el
método setDisabledTextColor para cambiar el color del texto en el área de texto JTextArea a negro para
mejorar la legibilidad.
Los métodos keyPressed (líneas 31 a 37) y keyReleased (líneas 40 a 46) utilizan el método getKeyCode
de KeyEvent para obtener el código de tecla virtual de la tecla oprimida. La clase KeyEvent mantiene un
conjunto de constantes de códigos virtuales que representan a todas las teclas en el teclado. Estas constan-
tes pueden compararse con el valor de retorno de getKeyCode para probar teclas individuales en el teclado.
El valor devuelto por getKeyCode se pasa al método getKeyText de KeyEvent, el cual devuelve una cadena
que contiene el nombre de la tecla que se oprimió. Para obtener una lista completa de las constantes de
teclas virtuales, vea la documentación en línea para la clase KeyEvent (paquete java.awt.event). El mé-
todo keyTyped (líneas 49 a 54) utiliza el método getKeyChar de KeyEvent (el cual devuelve un valor char)
para obtener el valor Unicode del carácter escrito.
Los tres métodos manejadores de eventos terminan llamando al método establecerLineas2y3 (líneas
57 a 69) y le pasan el objeto KeyEvent. Este método utiliza el método isActionKey de KeyEvent (línea 60)
para determinar si la tecla en el evento fue una tecla de acción. Además, se hace una llamada al método get-
Modifiers de InputEvent (línea 62) para determinar si se oprimió alguna tecla modificadora (como Mayús,
Alt y Ctrl) cuando ocurrió el evento de tecla. El resultado de este método se pasa al método getKeyModifiers-
Text de KeyEvent, el cual produce un objeto String que contiene los nombres de las teclas modificadoras
que se oprimieron.
[Nota: si necesita probar una tecla específica en el teclado, la clase KeyEvent proporciona una cons-
tante de tecla para cada tecla del teclado. Estas constantes pueden utilizarse desde los manejadores de
eventos de teclas para determinar si se oprimió una tecla específica. Además, para determinar si las teclas
Alt, Ctrl, Meta y Mayús se oprimen individualmente, cada uno de los métodos isAltDown, isControlDown,
isMetaDown e isShiftDown devuelven un valor boolean, indicando si se oprimió dicha tecla durante el
evento de tecla].
clase Container toma un objeto que implementa a la interfaz LayoutManager como argumento. Básica-
mente, existen tres formas para poder ordenar los componentes en una GUI:
1. Posicionamiento absoluto: esto proporciona el mayor nivel de control sobre la apariencia de una
GUI. Al establecer el esquema de un objeto Container en null, podemos especificar la posición
absoluta de cada componente de la GUI con respecto a la esquina superior izquierda del objeto
Container, usando los métodos setSize y setLocation o setBounds de Component. Si hacemos
esto, también debemos especificar el tamaño de cada componente de la GUI. La programación
de una GUI con posicionamiento absoluto puede ser un proceso tedioso, a menos que se cuente
con un entorno de desarrollo integrado (IDE), que pueda generar el código por nosotros.
2. Administradores de esquemas: el uso de administradores de esquemas para posicionar elementos
puede ser un proceso más simple y rápido que la creación de una GUI con posicionamiento ab-
soluto, pero se pierde cierto control sobre el tamaño y el posicionamiento preciso de los compo-
nentes de la GUI.
3. Programación visual en un IDE: los IDE proporcionan herramientas que facilitan la creación de
GUI. Por lo general, cada IDE proporciona una herramienta de diseño de GUI que nos permi-
te arrastrar y soltar componentes de GUI desde un cuadro de herramientas hacia un área de dise-
ño. Después podemos posicionar, ajustar el tamaño de los componentes de la GUI y alinearlos
según lo deseado. El IDE genera el código de Java que crea la GUI. Además, por lo general pode-
mos agregar código manejador de eventos para un componente específico, haciendo doble clic en
el componente. Algunas herramientas de diseño también nos permiten utilizar los administrado-
res de esquemas descritos en este capítulo y en el capítulo 22.
En la figura 12.38 se sintetizan los administradores de esquemas presentados en este capítulo. En el capí-
tulo 22 en línea hablaremos sobre un par de administradores de esquemas adicionales.
12.18.1 FlowLayout
Éste es el administrador de esquemas más simple. Los componentes de la GUI se colocan en un contenedor,
de izquierda a derecha, en el orden en el que se agregaron. Cuando se llega al borde del contenedor, los
componentes siguen mostrándose en la siguiente línea. La clase FlowLayout permite a los componentes de
la GUI alinearse a la izquierda, al centro (el valor predeterminado) y a la derecha.
La aplicación de las figuras 12.39 y 12.40 crea tres objetos JButton y los agrega a la aplicación, utili-
zando un administrador de esquemas FlowLayout. Los componentes se alinean hacia el centro de manera
predeterminada. Cuando el usuario hace clic en Izquierda, la alineación del administrador de esquemas
cambia a un FlowLayout alineado a la izquierda. Cuando el usuario hace clic en Derecha, la alineación del
administrador de esquemas cambia a un FlowLayout alineado a la derecha. Cuando el usuario hace clic en
Centro, la alineación del administrador de esquemas cambia a un FlowLayout alineado hacia el centro. Las
ventanas de salida de ejemplo muestran cada una de las alineaciones. La última ventana de salida de ejem-
plo muestra la alineación centrada después de ajustar el tamaño de la ventana a una anchura menor, de
modo que el botón Derecha fluya hacia una nueva línea.
Como se vio antes, el esquema de un contenedor se establece mediante el método setLayout de la
clase Container. En la línea 25 (figura 12.39) se establece el administrador de esquemas en FlowLayout,
el cual se declara en la línea 23. Por lo general, el esquema se establece antes de agregar cualquier compo-
nente de la GUI a un contenedor.
Fig. 12.39 冷 FlowLayout permite que los componentes fluyan a través de varias líneas (parte 1 de 2).
Fig. 12.39 冷 FlowLayout permite que los componentes fluyan a través de varias líneas (parte 2 de 2).
El manejador de eventos de cada botón se especifica con un objeto de una clase interna anónima
independiente (líneas 30 a 43, 48 a 61 y 66 a 79, respectivamente) y el método actionPerformed en
cada caso ejecuta dos instrucciones. Por ejemplo, la línea 37 en el manejador de eventos para el botón
botonJButtonIzquierda utiliza el método setAlignment de FlowLayout para cambiar la alineación del
objeto FlowLayout a la izquierda (FlowLayout.LEFT). En la línea 40 se utiliza el método layoutContainer
de la interfaz LayoutManager (que todos los administradores de esquemas heredan) para especificar
que el objeto JFrame debe reordenarse, con base en el esquema ajustado. Dependiendo del botón opri-
mido, el método actionPerformed para cada botón establece la alineación del objeto FlowLayout a
FlowLayout.LEFT (línea 37), FlowLayout.CENTER (línea 55) o FlowLayout.RIGHT (línea 73).
12.18.2 BorderLayout
El administrador de esquemas BorderLayout (el predeterminado para un objeto JFrame) ordena los
componentes en cinco regiones: NORTH, SOUTH, EAST, WEST y CENTER. NORTH corresponde a la parte supe-
rior del contenedor. La clase BorderLayout extiende a Object e implementa a la interfaz LayoutManager2
(una subinterfaz de LayoutManager, que agrega varios métodos para un mejor procesamiento de los
esquemas).
Un BorderLayout limita a un objeto Container para que contenga cuando mucho cinco componentes;
uno en cada región. El componente que se coloca en cada región puede ser un contenedor, al cual
se pueden adjuntar otros componentes. Los componentes que se colocan en las regiones NORTH y SOUTH se
extienden horizontalmente hacia los lados del contenedor, y tienen la misma altura que los componentes
que se colocan en esas regiones. Las regiones EAST y WEST se expanden verticalmente entre las regiones
NORTH y SOUTH, y tienen la misma anchura que los componentes que se coloquen dentro de ellas. El com-
ponente que se coloca en la región CENTER se expande para rellenar todo el espacio restante en el esquema (esto
explica por qué el objeto JTextArea de la figura 12.37 ocupa toda la ventana). Si las cinco regiones están
ocupadas, todo el espacio del contenedor se cubre con los componentes de la GUI. Si las regiones NORTH o
SOUTH no están ocupadas, los componentes de la GUI en las regiones EAST, CENTER y WEST se expanden
verticalmente para rellenar el espacio restante. Si las regiones EAST o WEST no están ocupadas, el componente
de la GUI en la región CENTER se expande horizontalmente para rellenar el espacio restante. Si la región CENTER
no está ocupada, el área se deja vacía; los demás componentes de la GUI no se expanden para rellenar
el espacio restante. La aplicación de las figuras 12.41 y 12.42 demuestra el administrador de esquemas
BorderLayout mediante el uso de cinco objetos JButton.
En la línea 21 de la figura 12.41 se crea un objeto BorderLayout. Los argumentos del constructor es-
pecifican el número de píxeles entre los componentes que se ordenan en forma horizontal (espacio libre
horizontal) y entre los componentes que se ordenan en forma vertical (espacio libre vertical), respectiva-
mente. El valor predeterminado es un píxel de espacio libre horizontal y vertical. En la línea 22 se utiliza el
método setLayout para establecer el esquema del panel de contenido en esquema.
Agregamos objetos Component a un objeto BorderLayout con otra versión del método add de
Container que toma dos argumentos: el objeto Component que se va a agregar y la región en la que
debe aparecer este objeto. Por ejemplo, en la línea 32 se especifica que botones[0] debe aparecer en la
región NORTH. Los componentes pueden agregarse en cualquier orden, pero sólo debe agregarse un com-
ponente a cada región.
espacio horizontal
espacio
vertical
12.18.3 GridLayout
El administrador de esquemas GridLayout divide el contenedor en una cuadrícula, de manera que los
componentes puedan colocarse en filas y columnas. La clase GridLayout hereda directamente de la clase
Object e implementa a la interfaz LayoutManager. Todo objeto Component en un objeto GridLayout
tiene la misma anchura y altura. Los componentes se agregan a un objeto GridLayout empezando en
la celda superior izquierda de la cuadrícula, y procediendo de izquierda a derecha hasta que la fila esté
llena. Después el proceso continúa de izquierda a derecha en la siguiente fila de la cuadrícula, y así sucesi-
vamente. La aplicación de las figuras 12.43 y 12.44 demuestra el administrador de esquemas GridLayout,
utilizando seis objetos JButton.
En las líneas 24 y 25 (figura 12.43) se crean dos objetos GridLayout. El constructor de GridLayout
que se utiliza en la línea 24 especifica un objeto GridLayout con 2 filas, 3 columnas, 5 píxeles de espacio
libre horizontal entre objetos Component en la cuadrícula y 5 píxeles de espacio libre vertical entre objetos
Component en la cuadrícula. El constructor de GridLayout que se utiliza en la línea 25 especifica un objeto
GridLayout con 3 filas y 2 columnas que utiliza el espacio libre predeterminado (1 píxel).
Los objetos JButton en este ejemplo se ordenan en un principio utilizando cuadricula1 (que se
establece para el panel de contenido en la línea 27, mediante el método setLayout). El primer compo-
nente se agrega a la primera columna de la primera fila. El siguiente componente se agrega a la segunda
columna de la primera fila, y así en lo sucesivo. Cuando se oprime un objeto JButton, se hace una lla-
mada al método actionPerformed (líneas 39 a 49). Todas las llamadas a actionPerformed alternan el
esquema entre cuadricula2 y cuadricula1, utilizando la variable boolean llamada alternar para de-
terminar el siguiente esquema a establecer.
En la línea 48 se muestra otra manera para cambiar el formato a un contenedor para el cual haya cam-
biado el esquema. El método validate de Container recalcula el esquema del contenedor, con base en el
administrador de esquemas actual para ese objeto Container y el conjunto actual de componentes de la
GUI que se muestran en pantalla.
Fig. 12.45 冷 Jpanel con cinco objetos JButton, en un esquema GridLayout adjunto a la región SOUTH
de un esquema BorderLayout.
6 {
7 public static void main(String[] args)
8 {
9 MarcoPanel marcoPanel = new MarcoPanel();
10 marcoPanel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
11 marcoPanel.setSize(450, 200);
12 marcoPanel.setVisible(true);
13 }
14 } // fin de la clase DemoPanel
Una vez que el objeto JPanel llamado panelBotones se declara (línea 11 de la figura 12.45) y se
crea (línea 19), en la línea 20 se establece el esquema de panelBotones a un GridLayout con una fila
y cinco columnas (hay cinco objetos JButton en el arreglo botones). En las líneas 23 a 27 se agregan
los cinco objetos JButton en el arreglo al objeto JPanel. En la línea 26 se agregan los botones directa-
mente al objeto JPanel (la clase JPanel no tiene un panel de contenido, a diferencia de JFrame). En la
línea 29 se utiliza el objeto BorderLayout predeterminado de JFrame para agregar panelBotones a
la región SOUTH. Esta región tiene la misma altura que los botones en panelBotones. Un objeto JPanel
ajusta su tamaño de acuerdo con los componentes que contiene. A medida que se agregan más compo-
nentes, el objeto JPanel crece (de acuerdo con las restricciones de su administrador de esquemas) para
dar cabida a esos nuevos componentes. Ajuste el tamaño de la ventana para que vea cómo el adminis-
trador de esquemas afecta al tamaño de los objetos JButton.
12.20 JTextArea
Un objeto JTextArea proporciona un área para manipular varias líneas de texto. Al igual que la clase
JTextField, JTextArea es una subclase de JTextComponent, el cual declara métodos comunes para
objetos JTextField, JTextArea y varios otros componentes de GUI basados en texto.
La aplicación en las figuras 12.47 y 12.48 demuestra el uso de los objetos JTextArea. Un objeto
JTextArea muestra texto que el usuario puede seleccionar. El otro no puede editarse, y se utiliza para
mostrar el texto que seleccionó el usuario en el primer objeto JTextArea. A diferencia de los objetos
JTextField, los objetos JTextArea no tienen eventos de acción, ya que al oprimir Intro mientras escribe
en un objeto JTextArea, el cursor simplemente avanza a la siguiente línea. Al igual que con los objetos
JList de selección múltiple (sección 12.13), un evento externo de otro componente de GUI indica
cuándo se debe procesar el texto en un objeto JTextArea. Por ejemplo, al escribir un mensaje de correo
electrónico, por lo general hacemos clic en un botón Enviar para enviar el texto del mensaje al destina-
tario. De manera similar, al editar un documento en un procesador de palabras, por lo general guarda-
mos el archivo seleccionando un elemento de menú llamado Guardar o Guardar como…. En este
programa, el botón Copiar>>> genera el evento externo que copia el texto seleccionado en el objeto
JTextArea de la izquierda, y lo muestra en el objeto JTextArea de la derecha.
En el constructor (líneas 18 a 48), la línea 21 crea un contenedor Box (paquete javax.swing) para
organizar los componentes de la GUI. Box es una subclase de Container que utiliza un administrador de
esquemas BoxLayout (que veremos con detalle en la sección 22.9) para ordenar los componentes de la GUI,
ya sea en forma horizontal o vertical. El método static createHorizontalBox de Box crea un objeto Box
que ordena los componentes de izquierda a derecha, en el orden en el que se adjuntan.
En las líneas 26 y 43 se crean los objetos JTextArea llamados areaTexto1 y areaTexto2. La línea
26 utiliza el constructor con tres argumentos de JTextArea, el cual recibe un objeto String que repre-
senta el texto inicial y dos valores int que especifican que el objeto JTextArea tiene 10 filas y 15 colum-
nas. En la línea 43 se utiliza el constructor con dos argumentos de JTextArea, el cual especifica que el
objeto JTextArea tiene 10 filas y 15 columnas. En la línea 26 se especifica que demo debe mostrarse como
el contenido predeterminado del objeto JTextArea. Un objeto JTextArea no proporciona barras de
desplazamiento si no puede mostrar su contenido completo. Por lo tanto, en la línea 27 se crea un obje-
to JScrollPane, se inicializa con areaTexto1 y se adjunta al contenedor cuadro. En un objeto JScroll-
Pane aparecen de manera predeterminada las barras de desplazamiento horizontal y vertical, según sea
necesario.
En las líneas 29 a 41 se crea el objeto JButton llamado botonCopiar con la etiqueta “Copiar >>>”,
se agrega botonCopiar al contenedor cuadro y se registra el manejador de eventos para el evento Action-
Event de botonCopiar. Este botón proporciona el evento externo que determina cuándo debe copiar el
programa el texto seleccionado en areaTexto1 a areaTexto2. Cuando el usuario hace clic en boton-
Copiar, la línea 38 en actionPerformed indica que el método getSelectedText (que hereda JTextArea
de JTextComponent) debe devolver el texto seleccionado de areaTexto1. Para seleccionar el texto, el
usuario arrastra el ratón sobre el texto deseado para resaltarlo. El método setText cambia el texto
en areaTexto2 por la cadena que devuelve getSelectedText.
En las líneas 43 a 45 se crea areaTexto2, se establece su propiedad editable en false y se agrega al
contenedor box. En la línea 47 se agrega cuadro al objeto JFrame. En la sección 12.18.2 vimos que el es-
quema predeterminado de un objeto JFrame es BorderLayout, y que el método add adjunta de manera
predeterminada su argumento a la región CENTER de este esquema.
Cuando el texto llega al extremo derecho de un objeto JTextArea, puede recorrerse a la siguiente línea.
A esto se le conoce como ajuste de línea. La clase JTextArea no ajusta las líneas de manera predeterminada.
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS
para indicar que siempre debe aparecer una barra de desplazamiento, las constantes
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
para indicar que debe aparecer una barra de desplazamiento sólo si es necesario (los valores predeterminados),
y las constantes
JScrollPane.VERTICAL_SCROLLBAR_NEVER
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
para indicar que nunca debe aparecer una barra de desplazamiento. Si la política de la barra de desplazamien-
to horizontal se establece en JScrollPane.HORIZONTAL_SCROLLBAR_NEVER, un objeto JTextArea adjunto
al objeto JScrollPane ajustará las líneas de manera automática.
12.21 Conclusión
En este capítulo aprendió muchos componentes de la GUI, y cómo implementar el manejo de eventos.
También aprendió las clases anidadas, las clases internas y las clases internas anónimas. Vio la relación
especial entre un objeto de la clase interna y un objeto de su clase de nivel superior. Aprendió a utilizar
diálogos JOptionPane para obtener datos de entrada de texto del usuario, y cómo mostrar mensajes a éste.
También aprendió a crear aplicaciones que se ejecuten en sus propias ventanas. Hablamos sobre la clase
JFrame y los componentes que permiten a un usuario interactuar con una aplicación. También le enseña-
mos cómo mostrar texto e imágenes al usuario. Vimos cómo personalizar los objetos JPanel para crear áreas
de dibujo personalizadas, las cuales utilizará ampliamente en el siguiente capítulo. Vio cómo organizar
los componentes en una ventana mediante el uso de los administradores de esquemas, y cómo crear GUI
más complejas mediante el uso de objetos JPanel para organizar los componentes. Por último, aprendió
acerca del componente JTextArea, en el cual un usuario puede introducir texto y una aplicación puede
mostrarlo. En el capítulo 22 aprenderá acerca de los componentes de GUI más avanzados, como los boto-
nes deslizables, los menús y los administradores de esquemas más complicados. En el siguiente capítulo
aprenderá a agregar gráficos a su aplicación de GUI. Los gráficos nos permiten dibujar figuras y texto con
colores y estilos.
Resumen
swing.defaultlaf=com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel
• Para seleccionar Nimbus en cada aplicación por separado, coloque el siguiente argumento de línea de comandos
después del comando java y antes del nombre de la aplicación, al momento de ejecutarla:
-Dswing.defaultlaf=com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel
• Las alineaciones horizontal y vertical de un objeto JLabel se pueden establecer mediante los métodos setHori-
zontalAlignment (pág. 484) y setVerticalAlignment (pág. 484), respectivamente.
• Los métodos setText (pág. 484) y getText (pág. 484) de JLabel establecen y obtienen el texto a mostrar en una
etiqueta.
• Los métodos setIcon (pág. 484) y getIcon (pág. 484) de JLabel establecen y obtienen el objeto Icon (pág. 484)
en una etiqueta.
• Los métodos setHorizontalTextPosition (pág. 484) y setVerticalTextPosition (pág. 484) de JLabel especifi-
can la posición del texto en la etiqueta.
• El método setDefaultCloseOperation (pág. 485) de JFrame, con la constante Frame.EXIT_ON_CLOSE como argu-
mento, indica que el programa debe terminar cuando el usuario cierre la ventana.
• El método setSize de Component (pág. 485) especifica la anchura y la altura de un componente.
• El método setVisible (pág. 485) de Component con el argumento true muestra un objeto JFrame en la pantalla.
Sección 12.6 Campos de texto y una introducción al manejo de eventos con clases anidadas
• Las GUI se controlan por eventos, lo que significa que cuando el usuario interactúa con un componente de GUI,
los eventos (pág. 485) controlan al programa para realizar las tareas.
• Un manejador de eventos (pág. 485) realiza una tarea en respuesta a un evento.
• La clase JTextField (pág. 485) extiende a la clase JTextComponent (pág. 485) del paquete javax.swing.text, que
proporciona muchas características comunes para los componentes de Swing basados en texto. La clase JPassword-
Field (pág. 485) extiende a JTextField y agrega varios métodos específicos para el procesamiento de contraseñas.
• Un objeto JPasswordField (pág. 485) muestra que se están escribiendo caracteres a medida que el usuario los in-
troduce, pero oculta los caracteres reales con caracteres de eco (pág. 485).
• Un componente recibe el enfoque (pág. 486) cuando el usuario hace clic sobre él.
• El método setEditable de JTextComponent (pág. 488) puede usarse para hacer que un campo de texto no pueda
editarse.
• Para responder a un evento para un componente específico de la GUI, debemos crear una clase que represente al
manejador de eventos e implementar una interfaz de escucha de eventos apropiada (pág. 488), después debemos
registrar un objeto de la clase manejadora de eventos como el manejador de eventos (pág. 488).
• Las clases anidadas no static (pág. 488) se llaman clases internas, y se utilizan con frecuencia para el manejo de
eventos.
• Un objeto de una clase no static interna (pág. 488) debe crearse mediante un objeto de la clase de nivel superior
(pág. 488), que contenga a la clase interna.
• Un objeto de la clase interna puede acceder directamente a todas las variables y métodos de su clase de nivel
superior.
• Una clase anidada que sea static no requiere un objeto de su clase de nivel superior, y no tiene una referencia
implícita a un objeto de la clase de nivel superior.
• Cuando el usuario oprime Intro en un objeto JTextField o JPasswordField, el componente de la GUI genera un
evento ActionEvent (pág. 489) que puede ser manejado por un objeto ActionListener (pág. 489) del paquete
java.awt.event.
• El método addActionListener de JTextField (pág. 489) registra el manejador de eventos para un campo de texto
de ActionEvent.
• El componente de GUI con el que interactúa el usuario es el origen del evento (pág. 490).
• Un objeto ActionEvent contiene información acerca del evento que acaba de ocurrir, como el origen del evento y
el texto en el campo de texto.
• El método getSource de ActionEvent devuelve una referencia al origen del evento. El método getActionCommand
(pág. 490) de ActionEvent devuelve el texto que escribió el usuario en un campo de texto o en la etiqueta de un
objeto JButton.
• El método getPassword de JPasswordField (pág. 490) devuelve la contraseña que escribió el usuario.
• Los objetos JRadioButton tienen dos estados: seleccionado y no seleccionado. Por lo general, los botones de opción
(pág. 495) aparecen como un grupo (pág. 501), en el cual sólo puede seleccionarse un botón a la vez.
• Los objetos JRadioButton se utilizan para representar opciones mutuamente excluyentes (pág. 501).
• La relación lógica entre los objetos JRadioButton se mantiene mediante un objeto ButtonGroup (pág. 501).
• El método add de ButtonGroup (pág. 504) asocia a cada objeto JRadioButton con un objeto ButtonGroup. Si se
agrega más de un objeto JRadioButton seleccionado a un grupo, el primer objeto JRadioButton seleccionado que
se agregue será el que quede seleccionado cuando se muestre la GUI en pantalla.
• Los objetos JRadioButton generan eventos ItemEvent cuando se hace clic sobre ellos.
Sección 12.11 JComboBox: uso de una clase interna anónima para el manejo de eventos
• Un objeto JComboBox (pág. 504) proporciona una lista de elementos, de los cuales el usuario puede seleccionar uno.
Los objetos JComboBox generan eventos ItemEvent.
• Cada elemento en un objeto JComboBox tiene un índice (pág. 507). El primer elemento que se agrega a un objeto
JComboBox aparece como el elemento actualmente seleccionado cuando se muestra el objeto JComboBox.
• El método setMaximumRowCount de JComboBox (pág. 507) establece el máximo número de elementos a mostrar
cuando el usuario haga clic en el objeto JComboBox.
• Una clase interna anónima (pág. 507) es una clase interna sin nombre y por lo general aparece dentro de la de-
claración de un método. Un objeto de la clase interna anónima debe crearse en el punto en el que se declara
la clase.
• El método getSelectedIndex de JComboBox (pág. 508) devuelve el índice del elemento seleccionado.
• Cuando el usuario hace clic en un elemento de un objeto JList, ocurre un evento ListSelectionEvent (pág. 508).
El método addListSelectionListener de JList (pág. 510) registra un objeto ListSelectionListener (pág. 510)
para los eventos de selección de un objeto JList. Un objeto ListSelectionListener del paquete javax.swing.
event (pág. 492) debe implementar el método valueChanged.
• El método setVisibleRowCount de JList (pág. 510) especifica el número de elementos visibles en la lista.
• El método setSelectionMode de JList (pág. 510) especifica el modo de selección de una lista.
• Un objeto JList se puede adjuntar a un JScrollPane (pág. 510) para proveer una barra de desplazamiento para
ese objeto JList.
• El método getContentPane de JFrame (pág. 510) devuelve una referencia al panel de contenido de JFrame, en
donde se muestran los componentes de la GUI.
• El método getSelectedIndex de JList (pág. 511) devuelve el índice del elemento seleccionado.
• Por lo general, un evento externo (pág. 513) generado por otro componente de la GUI (como un JButton) espe-
cifica cuándo deben procesarse las selecciones múltiples en un objeto JList.
• El método setListData de JList (pág. 513) establece los elementos a mostrar en un objeto JList. El método
getSelectedValues de JList (pág. 513) devuelve un arreglo de objetos Object que representan los elementos se-
leccionados en un objeto JList.
• La interfaz MouseInputListener (pág. 513) del paquete javax.swing.event extiende a las interfaces MouseListe-
ner y MouseMotionListener para crear una sola interfaz que contenga a todos sus métodos.
• Cada uno de los métodos manejadores de eventos del ratón recibe un objeto MouseEvent (pág. 494), el cual con-
tiene información acerca del evento, incluyendo las coordenadas x y y de la ubicación en donde ocurrió el evento.
Estas coordenadas se miden empezando desde la esquina superior izquierda del componente de la GUI en donde
ocurrió el evento.
• Los métodos y constantes de la clase InputEvent (pág. 514; superclase de MouseEvent) permiten a una aplicación
determinar cuál botón oprimió el usuario.
• La interfaz MouseWheelListener (pág. 515) permite a las aplicaciones responder a los eventos de la rueda de un ratón.
• La transparencia de un componente ligero de Swing puede establecerse con el método setOpaque (pág. 522; un
argumento false indica que el componente es transparente).
• La clase Point (pág. 523) del paquete java.awt representa una coordenada x-y.
• La clase Graphics (pág. 523) se utiliza para dibujar.
• El método getPoint de MouseEvent (pág. 524) obtiene el objeto Point en donde ocurrió un evento de ratón.
• El método repaint (pág. 524), heredado directamente de la clase Component, indica que un componente debe
actualizarse en la pantalla lo más pronto posible.
• El método paintComponent recibe un parámetro Graphics, y se llama automáticamente cada vez que un compo-
nente ligero necesita mostrarse en la pantalla.
• El método fillOval de Graphics (pág. 524) dibuja un óvalo relleno. Los primeros dos argumentos son la coorde-
nada x superior izquierda y la coordenada y superior izquierda del área rectangular delimitadora, mientras que las
últimas dos coordenadas representan la anchura y la altura del área rectangular.
• El método getKeyModifiersText (pág. 528) de KeyEvent produce una cadena que contiene los nombres de las
teclas modificadoras que se oprimieron.
• Un BorderLayout limita a un objeto Container para que contenga cuando mucho cinco componentes; uno en cada
región.
• GridLayout (pág. 536) divide un contenedor en una cuadrícula de filas y columnas.
• El método validate (pág. 537) de Container recalcula el esquema del contenedor, con base en el administrador de es-
quemas actual para ese objeto Container y el conjunto actual de componentes de la GUI que se muestran en pantalla.