Introducción a componentes Swing - Cómputo

comprende cualquier carácter que se pueda meter del teclado o aplicación, ... Cuando un JTextField tiene la capacidad de aceptar pulsaciones de teclas, ...
268KB Größe 17 Downloads 92 vistas
Introducci´on a componentes Swing H. Tejeda Mayo 2016

´Indice 1. Introducci´ on

1

2. Clase JFrame

2

3. Clase JLabel

6

4. Manejador de dise˜ no

9

5. Extensi´ on de la clase JFrame

11

6. Clases de entrada

13

7. Programaci´ on de manejo de eventos

17

8. Receptores de eventos

21

9. Clases para selecci´ on

23

1.

Introducci´ on

Las aplicaciones son m´ as amigables al usuario cuando estas contienen componentes interfaz de usuario o UI (User Interface). Los componentes UI son botones, campos de texto, y otros con los cuales el usuario puede interactuar. Los creadores de Java han empacado una cantidad de componentes preescritos en el paquete Swing. Los componentes Swing son elementos UI tales como cuadros de di´ alogo y botones; se reconocen porque sus nombres inician con J. Nota. Los componentes Swing fueron nombrados por un estilo musical que fue popular all´a en 1940. El nombre implica que los componentes tienen estilo y dinamismo. Las clases Swing son parte de un

1

conjunto m´as general de capacidades de programaci´on UI que son llamadas las clases de fundaci´ on Java o JFC (Java Foundation Classes). JFC incluye las clases componentes Swing y algunas clases del paquete java.awt.

Nota. En las primeras versiones de Java, los componentes ten´ıan nombres simples, tales como Frame y Button. Los componentes no ten´ıan una apariencia consistente cuando se usaban con diferentes navegadores y sistemas operativos. Cuando los programadores de Java dise˜ naron clases nuevas y mejoradas necesitaron nuevos nombres para las clases, as´ı que usaron una J precediendo cada nuevo nombre de clase. Por lo tanto, los componentes Swing tienen nombres como JFrame, JButton, JScrollbar, JOptionPane, etc.

Los componentes UI son tambi´en llamados controles o widgets (reproductores). Cada componente Swing es un descendiente de un JComponent, el cual a su vez hereda desde la clase java.awt.Container. Para usar los componentes UI Swing y sus m´etodos se debe insertar la sentencia import javax.swing.* al inicio del programa, de esta forma se importa el paquete. La x en el nombre del paquete representa la extensi´ on de las especificaciones del lenguaje Java original. Nota. Casi todos los componentes Swing se dice que son componentes peso ligero porque est´an escritos completamente en Java y no descansan en el c´odigo del sistema operativo local. Esto significa que los componentes no son “sobrecargados” teniendo que interactuar con el sistema operativo. Algunos componentes Swing, como JFrame, se conocen como componentes peso pesado porque requieren interactuar con el sistema operativo local. Un componente ligero reusa la ventana nativa de su ancestro m´as cercano peso pesado; un componente peso pesado tiene su propia ventana nativa opaca. Los u ´nicos componentes peso pesado usados en Swing son JFrame, JDialog, JWindow, JApplet, awt.Component, awt.Container, y JComponent.

Cuando se usan componentes Swing estos son puestos, generalmente, en contenedores. Un contenedor es un tipo de componente que guarda otros componentes para que este grupo pueda ser tratado como una sola entidad. Los contenedores est´an definidos en la clase Container. Frecuentemente, un contenedor toma la forma de una ventana que puede ser arrastrada, redimensionada, minimizada, restaurada, y cerrada. La clase Component es una hija de la clase Object, y la clase Container es una hija de la clase Component. Por lo tanto, cada objeto Container “es un” Component, y cada objeto Component “es un” Object. La clase Window es una hija de Container. Los programadores de Java usan poco los objetos Window porque la subclase Frame de Window y su subclase JFrame componente Swing, permiten crear objetos m´ as u ´tiles. Los objetos Window no tienen barra de t´ıtulo, ni bordes.

2.

Clase JFrame

Se crea un JFrame para poner otros objetos dentro para ser mostrados. Enseguida se muestra el ´arbol de herencia de la clase JFrame para mostrar la relaci´on con sus ancestros. java.lang.Object 2

| +--java.awt.Component | +---java.awt.Container | +---java.awt.Window | +---java.awt.Frame | +---javax.swing.JFrame La clase JFrame tiene cuatro constructores: JFrame() construye un nuevo marco que inicialmente es invisible y no tiene t´ıtulo. JFrame(String t´ ıtulo) crea un nuevo JFrame inicialmente invisible con el t´ıtulo indicado. JFrame(GraphicsConfiguration gc) crea un JFrame en el GraphicsConfiguration de un dispositivo de pantalla sin t´ıtulo. JFrame(String t´ ıtulo, GraphicsConfiguration gc) crea un JFrame con el t´ıtulo especificado y el GraphicsConfiguration dado de una pantalla. Se construye un JFrame como cualquier otro objeto, usando el nombre de la clase, un identificador, el operador de asignaci´ on, el operador new, y una llamada al constructor. Las siguientes dos sentencias construyen dos JFrame: uno con el t´ıtulo “Hola” y otro sin t´ıtulo. JFrame primerMarco = new JFrame("Hola"); JFrame segundoMarco = new JFrame(); Ya teniendo los objetos JFrame creados, se pueden usar algunos de los m´etodos u ´tiles dados en el cuadro 1. Suponiendo que se ha declarado un JFrame llamado primerMarco, se pueden usar las siguientes sentencias para poner el tama˜ no del objeto primerMarco a 250 p´ıxeles horizontalmente por 100 verticalmente y pone el t´ıtulo del JFrame para mostrar un argumento String. Los p´ıxeles son los elementos de imagen, o peque˜ nos puntos de luz, que hacen la imagen en el monitor de la computadora. primerMarco.setSize(250, 100); primerMarco.setTitle("Mi marco"); Cuando se pone el tama˜ no de un JFrame, no se tiene el ´area completa disponible para usarla porque parte del ´area es usada por la barra de t´ıtulo y los bordes del JFrame. La aplicaci´on JFrame1, c´ odigo 1, muestra una aplicaci´on que crea un JFrame peque˜ no y vac´ıo. 3

M´ etodo void setTitle(String) void setSize(int, int) void setSize(Dimension)

String getTitle() void setResizable(boolean)

boolean isResizable() void setVisible(boolean) void setBounds(int, int, int, int)

Descripci´ on Pone el t´ıtulo del JFrame usando el argumento String. Fija el tama˜ no de un JFrame en p´ıxeles con el ancho y alto como argumento. Fija el tama˜ no de un JFrame usando un objeto Dimension; el constructor Dimension(int, int) crea un objeto que representa un ancho y una altura. Regresa el t´ıtulo de un JFrame. Pone el JFrame para que sea redimensionable pasando true al m´etodo, con false es no redimensionable. Regresa true o false para indicar si el JFrame es redimensionable. Hace un JFrame visible usando el argumento booleano true e invisible usando el argumento false. Sobreescribe el comportamiento por defecto para que el JFrame sea posicionado en la esquina superior izquierda en la pantalla del escritorio de la computadora; los primeros dos argumentos son las posiciones horizontal y vertical de la esquina superior izquierda del JFrame en el escritorio, y los dos argumentos finales fijan el ancho y la altura.

Cuadro 1: M´etodos u ´tiles heredados por la clase JFrame.

4

1 2 3 4 5 6 7 8

import j a v a x . swing . ∗ ; public c l a s s JFrame1 { public s t a t i c void main ( S t r i n g [ ] a r g s ) { JFrame unMarco = new JFrame ( ” Primer Marco” ) ; unMarco . s e t S i z e ( 2 5 0 , 1 0 0 ) ; unMarco . s e t V i s i b l e ( true ) ; } }

C´ odigo 1: Aplicaci´on JFrame1. La aplicaci´on JFrame1, c´ odigo 1, crea un JFrame. Este se parece a marcos que se han visto cuando se usan programas UI diferentes. La raz´on para usar objetos marco similares es porque los usuarios ya est´an familiarizados con el ambiente de marcos. Cuando los usuarios ven marcos esperan ver una barra de t´ıtulo en la cima con informaci´on de texto. Tambi´en esperan ver los botones de minimizar, maximizar o restaurar, y cerrar en alguna de la esquinas superiores del marco. Muchos usuarios suponen que pueden cambiar el tama˜ no del marco arrastrando sus bordes o reposicionar la ventana en la pantalla arrastrando la barra de titulo de la ventana a una nueva localidad. En la aplicaci´ on del c´ odigo 1, las tres sentencias en el m´etodo main() son importantes. Despu´es de instancia unMarco, se necesita hacer setVisible(true) para poder ver el JFrame, y tambi´en poner su tama˜ no ya que de otra forma solo la barra de t´ıtulo del JFrame es visible porque el tama˜ no de este es 0 x 0 por defecto. Una raz´ on por la cual el JFrame es invisible es porque este se podr´ıa construir en segundo plano mientras otras acciones est´an ocurriendo y quiz´as se desear´ıa hacer visible m´ as tarde. Algunos programadores usan el m´etodo show() en vez del m´etodo setVisible(). Cuando un usuario cierra un JFrame pulsando en el bot´on cerrar en alguna de la esquinas superiores, el comportamiento por defecto para el JFrame es ocultarse y para la aplicaci´on continuar ejecut´andose. Esto tiene sentido cuando hay otras tareas por completar para el programa despu´es de que el marco principal fue cerrado—por ejemplo, mostrar marcos adicionales, cerrar archivos abiertos de datos, o imprimir un reporte de actividad. Cuando un JFrame sirve como una aplicaci´ on de Swing se quiere que el programa termine cuando el usuario pulsa el bot´on cerrar. Para cambiar el comportamiento se puede llamar al m´etodo setDefaultCloseOperation() de JFrame con alguno de los siguientes cuatro valores como argumento: JFrame.EXIT ON CLOSE termina el programa cuando el JFrame es cerrado. WindowConstants.DISPOSE ON CLOSE cierra el marco, dispone el objeto JFrame, y mantiene en ejecuci´ on la aplicaci´ on. WindowConstants.DO NOTHING ON CLOSE mantiene el JFrame abierto y contin´ ua ejecut´ andose. En otras palabras, deshabilita el bot´on cerrar. WindowConstants.HIDE ON CLOSE cierra el JFrame y contin´ ua ejecut´andose; este es el comportamiento por defecto. Cuando se ejecuta una aplicaci´ on en cual se ha olvidado salir cuando el JFrame es cerrado, se puede terminar el programa tecleando CTRL+C.

5

Personalizaci´ on de la apariencia de un JFrame La apariencia de un JFrame es dada por el sistema operativo en el cual el programa est´e ejecut´andose. El dise˜ no de los elementos que controlan el marco se parecen y se comportan como lo hace cualquier otra aplicaci´ on gr´ afica. Los botones y el ´ıcono, en el caso de que se muestre, son conocidos como decoraciones ventana; por defecto las decoraciones ventana son proporcionadas por el sistema operativo. Se puede pedir que el mirar y sentir de Java d´e las decoraciones para un marco. Un mirar y sentir es la apariencia y comportamiento por defecto de cualquier interfaz de usuario. Opcionalmente, se puede poner el mirar y sentir de un JFrame usando el m´etodo setDefaultLookAndFeelDecorated(). La aplicaci´ on JFrame2, c´odigo 2, hace una llamada a este m´etodo en la l´ınea 4. 1 2 3 4 5 6 7 8 9

import j a v a x . swing . ∗ ; public c l a s s JFrame2 { public s t a t i c void main ( S t r i n g [ ] a r g s ) { JFrame . s e t D e f a u l t L o o k A n d F e e l D e c o r a t e d ( true ) ; JFrame unMarco = new JFrame ( ” Segundo Marco” ) ; unMarco . s e t S i z e ( 2 5 0 , 1 0 0 ) ; unMarco . s e t V i s i b l e ( true ) ; } }

C´ odigo 2: La clase JFrame2. Puede ser que al usar el m´etodo setDefaultLookAndFeelDecorated() el sistema operativo impida modificar su apariencia, como en Mac OS X. Actividad 1. Escribir una aplicaci´ on gr´afica que muestre en el t´ıtulo de la ventana su nombre y tenga un tama˜ no cuadrado. Adem´ as la aplicaci´on debe terminar cuando se cierre el marco.

3.

Clase JLabel

Uno de los componentes que se podr´ıa poner en un JFrame es un JLabel. JLabel es una clase Swing incorporada que tiene texto que se quiere mostrar. La jerarqu´ıa de herencia de la clase JLabel se muestra enseguida: java.lang.Object | +--java.awt.Component | +---java.awt.Container | +---javax.swing.JComponent | +---javax.swing.JLabel

6

Los constructores para la clase JLabel incluyen los siguientes: JLabel() crea una instancia JLabel sin imagen con una cadena vac´ıa para el t´ıtulo. JLabel(Icon imagen) crea una instancia JLabel con la imagen especificada. JLabel(Icon imagen, int alineaci´ onHorizontal) crea una instancia JLabel con la imagen especificada y la alineaci´ on horizontal. JLabel(String texto) crea una instancia JLabel con el texto especificado. JLabel(String texto, Icon imagen, int alineaci´ onHorizontal) crea una instancia JLabel con el texto, la imagen, y la alineaci´on horizontal especificados. JLabel(String texto, int alineaci´ onHorizontal) crea una instancia JLabel con el texto y la alineaci´ on horizontal indicados. Se puede crear un JLabel llamado saludo que tenga las palabras “Buen d´ıa” con la siguiente sentencia: JLabel saludo = new JLabel("Buen d´ ıa"); Para agregar el objeto saludo al objeto JFrame llamado unMarco usando el m´ etodo add() como sigue: unMarco.add(saludo); La aplicaci´on JFrame3, c´ odigo 3, muestra la creaci´on de JFrame al que enseguida se le pone su tama˜ no y la operaci´ on de cierre. Luego un JLabel es creado y agregado al JFrame. 1 2 3 4 5 6 7 8 9 10 11 12 13

import j a v a x . swing . ∗ ; public c l a s s JFrame3 { public s t a t i c void main ( S t r i n g [ ] a r g s ) { f i n a l int ANCHO MARCO = 2 5 0 ; f i n a l int ALTO MARCO = 1 0 0 ; JFrame unMarco = new JFrame ( ” T e r c e r Marco” ) ; unMarco . s e t S i z e (ANCHO MARCO, ALTO MARCO) ; unMarco . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ; JLabel s a l u d o = new JLabel ( ”Buen d´ıa ” ) ; unMarco . add ( s a l u d o ) ; unMarco . s e t V i s i b l e ( true ) ; } }

C´ odigo 3: La clase JFrame3. La contraparte del m´etodo add() es el m´ etodo remove(). La siguiente sentencia quita saludo de unMarco:

7

unMarco.remove(saludo); Si se agrega, o quita un componente de un contenedor despu´es de que este se hizo visible, se deber´ıa tambi´en llamar los m´etodos invalidate(), validate() y repaint() para ver los resultados de las acciones. Cada uno realiza funciones ligeramente diferentes pero las tres juntas garantizan que el resultado de cambios en el dise˜ no tomar´an efecto. Los m´etodos invalidate() y validate() son parte de la clase Container, y repaint() es parte de la clase Component. Nota. Si se agrega o quita un componente en un objeto JFrame durante la construcci´on, no se tiene que llamar al m´etodo repaint() si despu´es se modifica el componente, como por ejemplo, cambiando el texto. S´ olo se necesita llamar a repaint() si se agrega o quita un componente despu´es de la construcci´ on.

Se puede cambiar el texto en un JLabel usando el m´ etodo setText() de la clase Component con el objeto JLabel y pas´ andole un String. El siguiente c´odigo cambia el valor mostrado en el JLabel saludo: saludo.setText("Suerte"); Se puede recuperar el texto en un JLabel, o cualquier otro Component, usando el m´ etodo getText(), el cual regresa el String guardado actualmente.

Cambiar la fuente de un JLabel Java proporciona una clase Font para crear un objeto que guarde el tipo de fuente, y la informaci´ on del estilo y del tama˜ no de la fuente. El m´ etodo setFont() requiere un argumento objeto Font. Para construir un objeto Font, se necesitan tres argumentos: tipo de fuente, estilo, y tama˜ no en puntos. El argumento tipo de fuente para el constructor Font es un String representando una fuente. Las fuentes comunes tienen nombres como Arial, Century, Monospaced, y Times New Roman. El argumento tipo de fuente es solo una petici´on; el sistema operativo en el cual el programa se ejecuta podr´ıa no tener acceso, y si es necesario, este lo sustituye con una fuente por defecto. El argumento estilo aplica un atributo al texto mostrado y es uno de tres valores: Font.PLAIN, Font.BOLD, o Font.ITALIC. El argumento tama˜ no en puntos es un entero que representa aproximadamente 1/72 de una pulgada. El texto impreso es generalmente de 12 puntos; una cabecera podr´ıa ser de 30 puntos. Nota. En impresi´ on, el tama˜ no de punto define una medida entre l´ıneas de texto en un documento de texto con interlineado simple. Java adopta la convenci´on de que un punto en una pantalla es equivalente a una unidad en las coordenadas del usuario.

8

Para dar a un objeto JLabel una nueva fuente, se puede crear un objeto Font, como en el siguiente: Font fuenteCabecera = new Font("Monospaced", Font.BOLD, 36); Luego se usa el m´etodo setFont() para asignar el objeto Font al objeto JLabel con una sentencia como la siguiente: saludo.setFont(fuenteCabecera); La aplicaci´on JFrame4, c´ odigo 4, muestra en las l´ıneas 2, 3, 7, 8, y 12 los cambios que se hicieron a JFrame3 para usar otro tipo de fuente con diferente tama˜ no y apariencia. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

import j a v a x . swing . ∗ ; import j a v a . awt . ∗ ; public c l a s s JFrame4 { public s t a t i c void main ( S t r i n g [ ] a r g s ) { f i n a l int ANCHO MARCO = 2 5 0 ; f i n a l int ALTO MARCO = 1 0 0 ; Font f u e n t e = new Font ( ” A r i a l ” , Font .BOLD, 3 6 ) ; JFrame unMarco = new JFrame ( ” Cuarta Ventana ” ) ; unMarco . s e t S i z e (ANCHO MARCO, ALTO MARCO) ; unMarco . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ; JLabel s a l u d o = new JLabel ( ”Buen d´ıa ” ) ; saludo . setFont ( fuente ) ; unMarco . add ( s a l u d o ) ; unMarco . s e t V i s i b l e ( true ) ; } }

C´ odigo 4: La clase JFrame4. No es obligatorio proporcionar un identificador para un objeto Font. Se pudo omitir la l´ınea 7 en el c´odigo 4 y poner la fuente en saludo con la siguiente sentencia, la cual usa un objeto Font an´onimo: saludo.setFont(new Font("Arial", Font.BOLD, 36)); Despu´es de crear un objeto Font, se puede crear un nuevo objeto con un tipo y tama˜ no diferente usando el m´etodo deriveFont() con los argumentos apropiados. Por ejemplo, las siguientes dos sentencias crean el objeto fuenteCabecera y el fuenteCuerpoTexto que est´a basado en el primer objeto: Font fuenteCabecera = new Font("Arial", Font.BOLD, 36); Font fuenteCuerpoTexto = fuenteCabecera.deriveFont(Font.PLAIN, 14);

4.

Manejador de dise˜ no

Cuando se quiere agregar m´ ultiples componentes a un JFrame u otro contenedor, usualmente se requiere proporcionar instrucciones para la colocaci´on de los componentes. En la aplicaci´on JFrame5, 9

c´odigo 5, dos JLabel son creados y agregados a un JFrame en las sentencias de las l´ıneas 11—12. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

import j a v a x . swing . ∗ ; public c l a s s JFrame5 { public s t a t i c void main ( S t r i n g [ ] a r g s ) { f i n a l int ANCHO MARCO = 2 5 0 ; f i n a l int ALTO MARCO = 1 0 0 ; JFrame unMarco = new JFrame ( ” Quinta Ventana ” ) ; unMarco . s e t S i z e (ANCHO MARCO, ALTO MARCO) ; unMarco . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ; JLabel s a l u d o = new JLabel ( ” Hola ” ) ; JLabel s a l u d o 2 = new JLabel ( ”¿Qui´en e r e s ? ” ) ; unMarco . add ( s a l u d o ) ; unMarco . add ( s a l u d o 2 ) ; unMarco . s e t V i s i b l e ( true ) ; } }

C´ odigo 5: La clase JFrame5. Cuando se ejecuta la aplicaci´ on JFrame5 s´olo la u ´ltima JLabel que fue agregada es visible, a pesar de que se agregaron dos etiquetas al marco. La segunda JLabel fue puesta encima de la primera, tap´andola completamente. Si se contin´ uan agregando m´as JLabel en el programa, s´olo la u ´ltima agregada al JFrame ser´ a visible. Para colocar m´ ultiples componentes en posiciones especificadas en un contenedor de tal forma que no se oculten entre ellas, se debe usar expl´ıcitamente un manejador de dise˜ no, una clase que controla el posicionamiento de componentes. El comportamiento por defecto de un JFrame es dado por un manejador llamado BorderLayout. Un manejador BorderLayout divide un contenedor en regiones. Cuando no se indica una regi´ on en la cual un componente se coloca, este se coloca siempre en el centro, y si estaba otro componente, lo tapa. Al agregar componentes usando el manejador FlowLayout, estos son colocados en un rengl´ on, y cuando el rengl´ on se llena, los componentes autom´aticamente se ponen en el siguiente rengl´on. Tres constantes est´ an definidas en la clase FlowLayout para indicar como los componentes son posicionados en cada rengl´ on de su contenedor. Estas son FlowLayout.LEFT, FlowLayout.RIGHT, y FlowLayout.CENTER. Para crear un manejador de dise˜ no llamado flujo que posicione los componentes a la derecha, se usa la siguiente sentencia: FlowLayout flujo = new FlowLayout(FlowLayout.RIGHT); En caso de no indicar como los componentes son distribuidos, por defecto estos son centrados en cada rengl´on. Una vez que el manejador de dise˜ no ha sido creado entonces puede ser puesto al objeto JFrame haciendo lo siguiente: unMarco.setLayout(flujo); Se puede compactar el c´ odigo usando un objeto FlowLayout an´onimo con: 10

unMarco.setLayout(new FlowLayout(FlowLayout.RIGHT)); La aplicaci´on JFrame6, c´ odigo 6, ha puesto el manejador de dise˜ no del JFrame para que componentes m´ ultiples sean visibles. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

import j a v a x . swing . ∗ ; import j a v a . awt . ∗ ; public c l a s s JFrame6 { public s t a t i c void main ( S t r i n g [ ] a r g s ) { f i n a l int ANCHO MARCO = 2 5 0 ; f i n a l int ALTO MARCO = 1 0 0 ; JFrame unMarco = new JFrame ( ” Sexta Ventana ” ) ; unMarco . s e t S i z e (ANCHO MARCO, ALTO MARCO) ; unMarco . s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ; JLabel s a l u d o = new JLabel ( ” Hola ” ) ; JLabel s a l u d o 2 = new JLabel ( ”¿Qui´en e r e s ? ” ) ; unMarco . s e t L a y o u t (new FlowLayout ( FlowLayout . RIGHT ) ) ; unMarco . add ( s a l u d o ) ; unMarco . add ( s a l u d o 2 ) ; unMarco . s e t V i s i b l e ( true ) ; } }

C´ odigo 6: La clase JFrame6. Al ejecutar la aplicaci´ on JFrame6 se deben ver los dos JLabel, uno al lado del otro porque se usa un FlowLayout. Si hubiera m´ as JLabel u otros componentes, estos ser´ıan colocados continuamente lado por lado a trav´es del JFrame hasta que no haya m´as espacio.

5.

Extensi´ on de la clase JFrame

Se puede instanciar un objeto JFrame simple dentro del m´etodo main() de una aplicaci´on o en cualquier otro m´etodo de cualquier clase que sea escrita. Alternativamente, se puede crear su propia clase que descienda de la clase JFrame. La ventaja de crear una clase hija desde JFrame es la posibilidad de poder poner las propiedades del JFrame dentro del constructor de objetos; luego, cuando se crea su objeto hijo JFrame, este es dotado autom´aticamente con las caracter´ısticas que se hayan especificado, tales como el tama˜ no, el t´ıtulo, y la operaci´on de cierre por defecto. Para crear una clase hija se usa la palabra reservada extends en la cabecera de la clase, seguido por el nombre de la clase padre. Para llamar el constructor de la clase padre se usa la palabra reservada super(), y deber´ a ser la primera sentencia en el constructor de la clase hija. La clase JMiMarco, c´ odigo 7, extiende a JFrame. En el constructor de JMiMarco, el constructor super() JFrame es llamado; este acepta un argumento String para usarlo como el t´ıtulo del JFrame. El constructor de JMiMarco tambi´en fija el tama˜ no, la operaci´on de cierre por defecto y la visibilidad para cada JMiMarco. Cada uno de los m´etodos—setSize(), setDefaultCloseOperation(), y setVisible—aparecen en el constructor sin un objeto, porque el objeto es el JMiMarco actual siendo construido.

11

1 2 3 4 5 6 7 8 9 10 11

import j a v a x . swing . ∗ ; public c l a s s JMiMarco extends JFrame { f i n a l int ANCHO = 2 0 0 ; f i n a l int ALTO = 1 2 0 ; public JMiMarco ( ) { super ( ”Mi marco ” ) ; s e t S i z e (ANCHO, ALTO) ; s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ; s e t V i s i b l e ( true ) ; } }

C´ odigo 7: La clase JMiMarco. Cuando se ejecuta la aplicaci´ on CrearDosObjetosMiMarco, c´odigo 8, los dos objetos JMiMarco son mostrados con el segundo encima del primero. Para ver el primer marco se debe arrastrar el segundo marco. 1 2 3 4 5 6

public c l a s s CrearDosObjetosMiMarco { public s t a t i c void main ( S t r i n g [ ] a r g s ) { JMiMarco miMarco = new JMiMarco ( ) ; JMiMarco miSegundoMarco = new JMiMarco ( ) ; } }

C´ odigo 8: La aplicaci´on CrearDosObjetosMiMarco.

Nota. Se podr´ıa usar el m´etodo setBounds() con uno de los objetos JMiMarco para no tener que arrastrar uno de los objetos JMiMarco para ver el otro. La clase Objeto incluye el m´etodo setLocation() que se puede usar con un JFrame. Para usar este m´etodo, se deben dar valores para las posiciones horizontal y vertical como argumentos del m´etodo. Nota. Se termina la aplicaci´ on cuando se pulsa en el bot´on cerrar de alguno de los dos objetos JMiMarco. Cada objeto tiene la misma operaci´on de cierre por defecto porque cada uno usa el mismo constructor que indica esa operaci´ on. Para permitir que s´olo un JMiMarco controle la terminaci´on del programa, se podr´ıa usar el m´etodo setDefaultCloseOperation() con alguno de los objetos en la aplicaci´ on para cambiar su comportamiento de cierre, quiz´as usando DISPOSE ON CLOSE para descartar uno de los marcos pero manteniendo la aplicaci´on en ejecuci´on.

Cuando se extiende un JFrame para crear una clase nueva personalizada, se debe recordar tomar decisiones con los atributos que se quieren fijar dentro de la clase y los que se quieren dejar a las aplicaciones que usar´ an la clase. Por ejemplo, se puede poner la sentencia setVisible() dentro del constructor de la clase hija JFrame, o se puede permitir a la aplicaci´on usar el m´etodo setVisible() precedido por el nombre de un objeto instanciado seguido de un punto. Cualquiera trabaja, pero si no se hace ninguna, el marco no ser´ a visible. Nota. Algunos programadores ponen un m´etodo main() dentro de una clase como JMiMarco. Luego la clase da la opci´ on para ser usada para instanciar objetos, como en la aplicaci´on CrearDosObjetosMiMarco, o para ser usada ejecut´andose como un programa que crea un objeto.

12

6.

Clases de entrada

Un JFrame tambi´en contiene otras caracter´ısticas de ventana, tales como JTextField, JButton, e informaci´on sobre herramientas (tool tips).

Clase JTextField Un JTextField es un componente en el cual un usuario puede teclear una l´ınea de texto. El texto comprende cualquier car´ acter que se pueda meter del teclado o aplicaci´on, incluyendo n´ umeros y signos de puntuaci´ on. La siguiente figura muestra la jerarqu´ıa de herencia de la clase JTextField. java.lang.Object | +--java.awt.Component | +---java.awt.Container | +---javax.swing.JComponent | +---javax.swing.text.JTextComponent | +---javax.swing.JTextField En un JTextField un usuario teclea una l´ınea de texto y luego presiona la tecla Intro o pulsa un bot´on con el rat´ on para meter los datos. Se puede construir un objeto JTextField usando uno de los varios constructores: JTextField() construye un nuevo JTextField. JTextField(int columnas) construye un nuevo JTextField vac´ıo con la cantidad indicada de columnas. JTextField(String texto) construye un nuevo JTextField inicializado con el texto especificado. JTextField(String texto, int columnas) construye un nuevo JTextField inicializado con el texto dado y la cantidad de columnas indicada. Por ejemplo, para tener un JTextField que tenga suficiente espacio para que un usuario puede meter 10 caracteres, se puede codificar lo siguiente: JTextField respuesta = new JTextField(10); Para agregar el JTextField llamado respuesta a un JFrame llamado marco, se indica con: 13

marco.add(respuesta); La cantidad de caracteres que un JTextField puede mostrar depende de la fuente usada y los caracteres tecleados. En la mayor´ıa de las fuentes, m es m´as ancha que i, as´ı un JTextField de tama˜ no 10 usando la fuente Arial puede mostrar 24 caracteres i, pero s´olo 8 caracteres m. Se debe intentar anticipar cuanto caracteres los usuarios podr´ıan ingresar cuando se crea un JTextField. El usuario puede meter m´as caracteres que aquellos que son mostrados, pero los caracteres extra se desplazan fuera de la vista. Puede ser desconcertante intentar meter datos en un campo que no es lo suficientemente grande, as´ı que es mejor sobreestimar que subestimar el tama˜ no de un campo de texto. Otros m´etodos est´ an disponibles para ser usados con objetos JTextField. El m´etodo setText() permite cambiar el texto en un JTextField, u otro Componet, que ha sido creado, como se muestra enseguida: respuesta.setText("Gracias"); Despu´es de que el usuario ingreso texto en un JTextField, se puede limpiar con una sentencia como la siguiente, la cual asigna una cadena vac´ıa al texto: respuesta.setText(""); El m´etodo getText() permite recuperar el String de texto en un JTextField, u otro Component, como en: String entradaUsuario = respuesta.getText(); Cuando un JTextField tiene la capacidad de aceptar pulsaciones de teclas, el JTextField es editable. Un JTextField por defecto es editable. Si no se quierer que el usuario pueda ingresar datos en un JTextField, se puede mandar un valor booleano al m´ etodo setEditable() para cambiar el estado editable de un JTextField. Por ejemplo, si se quiere dar al usuario una cantidad limitada de oportunidades de contestar una pregunta correctamente, se pueden contar los intentos de entrada de datos y entonces prevenir al usuario de reemplazar o editar los caracteres en el JTextField usando una sentencia como: if (intentos > LIMITE) respuesta.setEditable(false );

Clase JButton Un JButton es un Component en el cual el usuario puede pulsar con el rat´on para hacer una selecci´on. Hay cinco constructores JButton y son:

14

JButton() crea un bot´ on sin texto. JButton(Icon ´ ıcono) crea un bot´on con un ´ıcono de tipo Icon o ImageIcon. JButton(String texto) crea un bot´on con texto. JButton(String texto, Icon icon) crea un bot´on con el texto inicial y un ´ıcono del tipo Icon o ImageIcon. JButton(Action a) crea un bot´on en el cual sus propiedades son tomadas de la Action proporcionada. La jerarqu´ıa de herencia de la clase JButton es la siguiente: java.lang.Object | +--java.awt.Component | +---java.awt.Container | +---javax.swing.JComponent | +---javax.swing.AbstractButton | +---javax.swing.JButton Para crear un JButton con la etiqueta “Pulsar cuando est´e listo”, se puede escribir lo siguiente: JButton botonListo = new JButton("Pulsar cuando est´ e listo"); Se puede agregar un JButton a un JFrame usando el m´etodo add(). Se puede cambiar la etiqueta de un JButton con el m´etodo setText(), como en: botonListo.setText("¡No me presiones nuevamente!"); Se puede recuperar el texto de un JButton y asignarlo a un objeto String con el m´etodo getText(), usando: String queEstaEnJButton = botonListo.getText(); La clase JFrameConMuchosComponentes, c´odigo 9, extiende JFrame y guarda varios componentes. Como los componentes, dos JLabel, un JTextField y un JButton son agregados al marco, estos son puestos de izquierda a derecha en renglones horizontales en la superficie del JFrame.

15

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

import j a v a x . swing . ∗ ; import j a v a . awt . ∗ ; public c l a s s JFrameConMuchosComponentes extends JFrame { f i n a l int ANCHO = 3 5 0 ; f i n a l int ALTO = 1 5 0 ; public JFrameConMuchosComponentes ( ) { super ( ” Mostrar muchos componentes ” ) ; s e t S i z e (ANCHO, ALTO) ; s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ; JLabel c a b e c e r a = new JLabel ( ” Este marco t i e n e v a r i o s componentes ” ) ; c a b e c e r a . s e t F o n t (new Font ( ” A r i a l ” , Font .BOLD, 1 6 ) ) ; JLabel mensajeNombre = new JLabel ( ” I n g r e s a r su nombre : ” ) ; J T e x t F i e l d campoNombre = new J T e x t F i e l d ( 1 2 ) ; JButton boton = new JButton ( ” P u l s a r para c o n t i n u a r ” ) ; s e t L a y o u t (new FlowLayout ( ) ) ; add ( c a b e c e r a ) ; add ( mensajeNombre ) ; add ( campoNombre ) ; add ( boton ) ; } }

C´ odigo 9: La clase JFrameConMuchosComponentes. La aplicaci´on DemoComponentes, c´ odigo 10, instancia un objeto del tipo JFrameConMuchosComponentes. 1 2 3 4 5 6 7

public c l a s s DemoComponentes { public s t a t i c void main ( S t r i n g [ ] a r g s ) { JFrameConMuchosComponentes marco = new JFrameConMuchosComponentes ( ) ; marco . s e t V i s i b l e ( true ) ; } }

C´ odigo 10: Aplicaci´on DemoComponentes. Al ejecutar la aplicaci´ on DemoComponentes, el JFrame contiene todos los componentes que fueron agregados en el constructor del marco. El usuario puede minimizar o restaurar el marca y puede modificar su tama˜ no arrastrando los bordes del marco. El usuario puede teclea en el JTextField y pulsar el JButton. Cuando el bot´ on es pulsado, este parece que fue presionado al igual que otros botones usados en diferentes aplicaciones. Sin embargo, cuando el usuario teclea o pulsa el bot´ on, no ocurren acciones resultantes porque no se ha sido escrito todav´ıa c´odigo para manejar es eventos iniciados por usuario.

Uso de informaci´ on sobre herramientas Informaci´ on sobre herramientas (tool tips) son ventanas emergentes que pueden ayudar al usuario a entender el prop´ osito de los componentes en una aplicaci´on; la informaci´on aparece cuando un usuario flota el apuntador del rat´ on encima del componente. Se define el texto que ser´a mostrado en una sugerencia usando el m´ etodo setToolTipText() y pas´andole un String apropiado. En la clase JFrameConMuchosComponentes, c´odigo 9, se puede agregar una sugerencia al componente 16

boton usando la siguiente sentencia en el constructor JFrame: boton.setToolTipText("Pulsa este bot´ on"); Actividad 2. Crear una aplicaci´ on Swing que muestre un JFrame que tenga un JLabel, un JTextField, y un JButton. El dise˜ no de esta aplicaci´on deber´a incluir una clase que extienda a la clase JFrame, la cual tendr´ a los componentes como campos de esta clase con la correspondiente asignaci´on de los objetos instanciados; en el constructor de la clase hija configurar el marco y agregar los componentes. Luego escribir una aplicaci´on que cree un objeto de la clase hija donde se deber´a fijar el tama˜ no de la ventana en 350 de ancho y 100 de alto usando constantes.

7.

Programaci´ on de manejo de eventos

Un evento ocurre cuando un usuario realiza una acci´on en un componente, tal como pulsar el rat´on en un objeto JButton. En un programa de manejo de eventos, el usuario podr´ıa iniciar cualquier cantidad de eventos en cualquier orden. Si se usa un programa procesador de textos, se tienen docenas de opciones disponibles en cualquier momento. Se puede teclear texto, seleccionar el texto con el rat´ on, pulsar un bot´ on para cambiar el texto a negritas, o a it´alicas, escoger un elemento del men´ u, etc. Con cada documento creado se escogen opciones en el orden que parece m´as apropiado en el momento. El programa procesador de textos deber´a estar listo para responder cualquier evento que haya sido iniciado. Dentro de un programa de manejo de eventos, un componente en el cual un evento es generado es la fuente del evento. Un bot´ on que un usuario puede pulsar es un caso de una fuente; un campo de texto donde un usuario puede ingresar texto es otra fuente. Un objeto que est´a interesado en un evento es un receptor (listener ). No todos los objetos oyen por todos los posibles eventos—como en algunos programas en los cuales se pulsa en diferentes ´areas de la pantalla y no sucede nada. Si se quiere que un objeto sea un receptor para un evento, se debe registrar el objeto como un receptor de la fuente. Un objeto fuente componente Java, como un bot´on, mantiene una lista de receptores registrados y notifica a todos ellos cuando cualquier evento ocurre. Un JFrame podr´ıa querer ser notificado de cualquier pulsaci´ on en su superficie. Cuando un receptor “recibe las noticias”, un m´etodo de manejo de evento contenido en el objeto receptor responde al evento. Nota. Un objeto fuente y un objeto receptor puede ser el mismo objeto. Por ejemplo, se podr´ıa programar un JButton para cambiar su propia etiqueta cuando un usuario lo pulse.

Para responder a eventos del usuario dentro de alguna clase creada, se debe hacer lo siguiente: Preparar la clase para aceptar mensajes de eventos. Indicar a la clase para que espere eventos que pasar´an. Indicar a la clase como responder a los eventos. 17

Preparar la clase para aceptar mensajes de eventos Se prepara la clase para aceptar eventos de pulsaci´on del bot´on importando el paquete java.awt.event en el programa y agregando la frase implements ActionListener a la cabecera de la clase. En el paquete java.awt.event se incluyen clases evento como ActionEvent, ComponentEvent, y TextEvent. ActionListener es una interfaz—un tipo de clase con un conjunto de especificaciones para m´etodos que se pueden usar. Implementar ActionListener da especificaciones est´andar de m´etodos de eventos que permiten al receptor trabajar con ActionEvent, el cual es el tipo de evento que ocurre cuando se pulsa un bot´ on.

Indicar a la clase para que espere eventos que pasar´ an Se le dice a una clase que espere eventos ActionEvent con el m´ etodo addActionListener(). Si se ha declarado un JButton llamado unBoton, y se quiere realizar una acci´on cuando el usuario pulse unBoton, unBoton es la fuente de un mensaje, y se puede considerar a la clase como un destino al cual se manda este. La referencia this significa “este objeto actual”, as´ı el c´ odigo unBoton.addActionListener(this); hace que cualquier mensaje ActionEvent (pulsar bot´ on) que venga de unBoton sea enviado a “este objeto actual”. Nota. No todos los eventos son ActionEvent con un m´etodo addActionListener(). Por ejemplo, KeyListener tiene un m´etodo addKeyListener, y FocusListener tiene un m´etodo addFocusListener.

Indicar a la clase como responder a los eventos La interfaz ActionListener contiene la especificaci´on del m´ etodo actionPerformed(ActionEvent e). Cuando una clase, tal como un JFrame, fue registrada como un receptor para un Component, tal como un JButton, y un usuario pulsa el JButton, el m´etodo actionPerformed() se ejecuta. Se implementa el m´etodo actionPerformed() usando la siguiente cabecera, donde e representa cualquier nombre que se quiera para el evento que inici´o la notificaci´on al ActionListener, el cual es el JFrame: public void actionPerformed(ActionEvent e) El cuerpo del m´etodo contiene cualquier sentencia que se quiera ejecutar cuando la acci´on ocurre. Se podr´ıa querer realizar un c´ alculo matem´atico, construir nuevos objetos, generar salida, o ejecutar cualquier otra operaci´ on. En la clase JVentanaHola, c´odigo 11, un JFrame contiene un JLabel que pide al usuario un nombre, un JTextField en el cual el usuario puede teclear una respuesta, un JButton para pulsar, y una segunda JLabel que muestra el nombre ingresado por el usuario. El m´etodo actionPerformed() se ejecuta cuando el usuario pulsa el bot´on JButton; dentro del m´etodo, la cadena que un usuario ha tecleado en el JTextField es recuperada y guardada en la variable nombre. El nombre es luego usado como de un String que altera la segunda JLabel del JFrame.

18

1 2 3 4

j a v a x . swing . ∗ ; j a v a . awt . ∗ ; j a v a . awt . e v e n t . ∗ ; c l a s s JVentanaHola extends JFrame implements A c t i o n L i s t e n e r { JLabel p r e g u n t a = new JLabel ( ”¿Cu´a l e s su nombre ? ” ) ; Font fuenteGrande = new Font ( ” A r i a l ” , Font .BOLD, 1 6 ) ; J T e x t F i e l d r e s p u e s t a = new J T e x t F i e l d ( 1 0 ) ; JButton unBoton = new JButton ( ” Pulsa aqu´ı” ) ; JLabel s a l u d o = new JLabel ( ” ” ) ; f i n a l int ANCHO = 2 7 5 ; f i n a l int ALTURA = 2 2 5 ; public JVentanaHola ( ) { super ( ” Ventana Hola ” ) ; s e t S i z e (ANCHO, ALTURA) ; p r e g u n t a . s e t F o n t ( fuenteGrande ) ; s a l u d o . s e t F o n t ( fuenteGrande ) ; s e t L a y o u t (new FlowLayout ( ) ) ; add ( p r e g u n t a ) ; add ( r e s p u e s t a ) ; add ( unBoton ) ; add ( s a l u d o ) ; s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ; unBoton . a d d A c t i o n L i s t e n e r ( t h i s ) ; } public void a c t i o n P e r f o r m e d ( ActionEvent e ) { S t r i n g nombre = r e s p u e s t a . getText ( ) ; S t r i n g mensaje = ” Hola ” + nombre ; s a l u d o . s e t T e x t ( mensaje ) ; }

import import import public

5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

}

C´ odigo 11: La clase JVentanaHola. La aplicaci´on JDemoHola, c´ odigo 12, instancia un objeto JVentanaHola y lo hace visible. 1 2 3 4 5 6

public c l a s s JDemoHola { public s t a t i c void main ( S t r i n g [ ] a r g s ) { JVentanaHola ventana = new JVentanaHola ( ) ; ventana . s e t V i s i b l e ( true ) ; } }

C´ odigo 12: Aplicaci´on JDemoHola. Cuando se ejecuta la aplicaci´ on JDemoHola, la cual instancia un objeto JVentanaHola, despu´es de que el usuario ingresa un nombre, el programa lo saluda con el nombre despu´es de que el usuario pulsa el bot´ on. Cuando m´as de un componente es agregado y registrado a un JFrame, podr´ıa ser necesario determinar cual componente fue usado para iniciar un evento. En la clase JVentanaHola, c´ odigo jventanahola, se podr´ıa querer que el usuario pueda ver el mensaje despu´es de pulsar el bot´ on o de presionar la tecla Intro en el JTextField. En ese caso, se podr´ıa designar a ambos como fuentes

19

de mensaje usando el m´etodo addActionListener() con cada uno, como sigue: unBoton.addActionListener(this); respuesta.addActionListener(this); Estas dos sentencias hacen que el JFrame (this) el receptor de cualquier objeto. El JFrame tiene un s´olo m´etodo actionPerformed(), as´ı que este es el m´etodo que se ejecuta cuando el bot´on unBoton mande un mensaje o el campo de texto respuesta. Si se quiere que acciones diferentes ocurran dependiendo del generador del evento, se debe determinar la fuente del evento. Dentro del m´etodo actionPerformed(), se puede usar el m´etodo getSource() del objeto enviado para determinar cual componente gener´o el evento. Por ejemplo, dentro de un m´etodo con la cabecera public void actionPerformed(ActionEvent e), e es un ActionEvent. ActionEvent y otras clases evento son parte del paquete java.awt.event y son subclases de la clase EventObject. Para determinar cual objeto gener´o el ActionEvent, se usa la siguiente sentencia: Object fuente = e.getSource(); Por ejemplo, si un JFrame contiene dos JButton llamados opcion1 y opcion2, se puede usar la estructura de decisi´ on en el siguiente m´etodo para tomar diferentes acciones dependiendo del bot´ on pulsado. Si una fuente de evento es un JButton, JTextField, u otro Component, este puede ser asignado a un Object porque todos los componentes descienden de Object. public void actionPerformed(ActionEvent e) { Object fuente = e.getSource(); if (fuente == opcion1) // ejecutar estas sentencias cuando el usuario pulse opcion1 else // ejecutar estas sentencias cuando el usuario pulse opcion2 } Alternativamente, se puede tambi´en usar la palabra reservada instanceof para determinar la fuente del evento. instanceof es usada cuando es necesario conocer s´olo el tipo del componente, en vez del componente que dispar´ o el evento. Por ejemplo, si se quiere tomar alguna acci´on cuando un usuario ingresa datos en cualquier JTextField, pero no cuando un evento es generado por un tipo diferente de Component, se usa el formato de m´etodo mostrado enseguida: void actionPerformed(ActionEvent e) { Object fuente = e.getSource(); if (fuente instanceof JTextField) { // ejecutar las sentencias cuando cualquier // JTextField genera el evento, pero no cuando // un JButton u otro Component lo hace. } } 20

M´ etodo setEnabled() Cuando se usan aplicaciones hay ocasiones en las cuales un componente se deshabilita o deja de ser usable. Por ejemplo, un JButton podr´ıa oscurecerse y deja de responder cuando el programador no quiera que se tenga acceso a este. Los componentes est´an habilitados por defecto, pero se puede usar el m´etodo setEnabled() para hacer un componente disponible o no pasando true o false a este, respectivamente. Actividad 3. Agregar funcionalidad al JButton y al JTextField de la actividad 6. Al pulsar el bot´on o presionar la tecla Intro se deber´a cambiar el texto de la etiqueta para que muestre un mensaje de agradecimiento y para que el bot´on muestre la cadena “Hecho”. Actividad 4. Repetir la actividad anterior pero ahora s´olo se modificar´a el texto de la etiqueta para que indique quien fue la fuente del evento, si el bot´on o el campo de texto.

8.

Receptores de eventos

Varios tipos de receptores existen en Java, y cada uno de estos puede manejar un tipo de evento espec´ıfico. Una clase puede implementar tantos receptores como ocupe—por ejemplo, una clase podr´ıa requerir responder a la pulsaci´ on de un bot´on del rat´on y a un teclazo, as´ı que se deber´ an implementar las interfaces ActionListener y KeyListener. El cuadro 2 lista algunos receptores de eventos y los tipos de eventos para los cuales son usados. Receptor ActionListener AdjustmentListener

Tipos de eventos Eventos de acci´on Eventos de ajuste

ChangeListener FocusListener

Eventos de cambio Eventos del foco del teclado

ItemListener

Eventos de elementos

KeyListener MouseListener MouseMotionListener

Eventos Eventos Eventos rat´ on Eventos

WindowListener

del teclado del rat´on de movimiento del

Ejemplo Pulsar bot´on Mover barra de desplazamiento Reposicionar deslizador Gana o pierde el foco un campo de texto Cambiar estado de casilla de verificaci´on Ingresar texto Pulsar bot´on del rat´on Mover rat´on

de la ventana

Cerrar ventana

Cuadro 2: Lista de algunos receptores de eventos Un evento ocurre cada vez que un usuario teclea o pulsa un bot´on del rat´on. Cualquier objeto puede ser notificado de un evento siempre y cuando este implemente la interfaz apropiada y sea registrado como un receptor de eventos en la fuente de eventos apropiada. Previamente, en la secci´on 6, se ha mostrado como establecer una relaci´ on entre un JButton y un JFrame que lo contiene usando el m´etodo addActionListener(). De igual forma, se pueden crear relaciones entre otros componentes Swing y las clases que reaccionan a las manipulaciones de usuarios de ellos. En el cuadro 3, cada componente listado en la columna izquierda est´a asociado con un m´etodo de la columna derecha. 21

Por ejemplo, cuando se quiere que un JCheckBox responda a las pulsaciones del usuario, se puede usar el m´etodo addItemListener() para registrar el JCheckBox como el tipo de objeto que puede crear un evento ItemEvent. El argumento que se pone dentro de los par´entesis de la llamda al m´etodo addItemListener() es el objeto que deber´ıa responder al evento—quiz´as un JFrame que contiene el JCheckBox generador del evento. El formato es: laFuenteDelEvento.addListenerMetodo(laClaseQueDeber´ aResponder); Componente(s)

M´ etodo(s) registradoresreceptores asociados addActionListener()

JButton, JCheckBox, JComboBox, JTextField, y JRadioButton. JScrollBar Todos los componentes Swing.

addAdjustmentListener() addFocusListener(), addKeyListener(), addMouseListener(), y addMouseMotionListener() addItemListener()

JButton, JCheckBox, JComboBox, y JRadioButton. Todos los componentes JWindow y JFrame. JSlider y JCheckBox.

addWindowListener() addChangeListener()

Cuadro 3: Algunos componentes Swing y su m´etodos registradores-receptores asociados Nota. Cualquier fuente de eventos puede tener m´ ultipes receptores registrados en este.Es decir, una sola instancia de JCheckBox podr´ıa generar eventos ItemEvent y FocusEvent, y una sola instancia de la clase JFrame podr´ıa responder a los ActionEvent generados por el JButton y a los ItemEvents generados por el JCheckBox.

La clase del objeto que responde a un evento debe contener un m´etodo que acepte el objeto evento creado por la acci´ on del usuario. Un m´etodo que se ejecuta porque es llamado autom´aticamente cuando un evento apropiado ocurre es un manejador de evento. Es decir, cuando se registra un componente, tal como un JFrame, para ser un receptor para eventos generados por otro componente, como un JCheckBox, se debe escribir un m´etodo manejador de evento. No se puede escoger un nombre propio para los manejadores de evento—identificadores de m´etodos espec´ıficos reaccionan a tipos espec´ıficos de eventos. En el cuadro 4 se listan algunos de los m´etodos que reaccionan a eventos. Receptor ActionListener AdjustmentListener FocusListener ItemListener

M´ etodo actionPerformed(ActionEvent) adjustmentValueChanged(AdjustmentEvent) focusGained(FocusEvent) y focusLost(FocusEvent) itemStateChanged(ItemEvent)

Cuadro 4: M´etodos seleccionados que responden a eventos. Las siguientes tareas se deben realizar cuando se declara una clase que maneja un evento: 22

La clase que maneja un evento deber´a implementar una interfaz receptora o extender una clase que implemente una interfaz receptora. Por ejemplo, si un JFrame llamado MiMarco necesita responder a pulsaciones del usuario en un JCheckBox, se podr´ıa escribir la siguiente cabecera de clase: public class MiMarco extends JFrame implements ItemListener Si despu´es se declara una clase que extienda MiMarco, no se necesita incluir implements ItemListener en su cabecera. La nueva clase hereda la implementaci´on. Se debe registrar cada instancia de la clase manejadora de eventos como un receptor para uno o m´as componentes. Por ejemplo, si MiMarco contiene un JCheckBox llamado miCheckBox, entonces dentro de la clase MiMarco se podr´ıa codificar: miCheckBox.addItemListener(this); La referencia this es a la clase en la cual miCheckBox est´a declarado—en este caso, MiMarco. Se debe escribir un m´etodo manejador de eventos con un identificador apropiado, como se muestra en el cuadro 4, que acepte el evento generado y reaccione a este.

9.

Clases para selecci´ on

Otros componentes permiten al usuario hacer selecciones en un ambiente interfaz de usuario, como JCheckBox, ButtonGroup, y JComboBox.

Clase JCheckBox Un JCheckBox es una casilla de verificaci´on que consiste de una etiqueta puesta a un lado de un cuadro; se puede pulsar el cuadro para mostrar una palomita o quitarla. Se usa un JCheckBox para permitir al usuario prender o apagar una opci´on. La aplicaci´on DemoCheckBox, c´odigo 13, muestra el uso de cuatro JCheckBox.

23

1 2 3 4

j a v a . awt . ∗ ; j a v a x . swing . ∗ ; j a v a . awt . e v e n t . ∗ ; c l a s s DemoCheckBox extends JFrame implements I t e m L i s t e n e r { JLabel e t i q u e t a = new JLabel ( ”¿Qu´e d e s e a s tomar ? ” ) ; JCheckBox c a f e = new JCheckBox ( ” Caf´e” , f a l s e ) ; JCheckBox c o l a = new JCheckBox ( ” Cola ” , f a l s e ) ; JCheckBox l e c h e = new JCheckBox ( ” Leche ” , f a l s e ) ; JCheckBox agua = new JCheckBox ( ”Agua” , f a l s e ) ; JLabel e s t a d o = new JLabel ( ” ” ) ; public DemoCheckBox ( ) { super ( ” Demostraci´ on CheckBox” ) ; s e t D e f a u l t C l o s e O p e r a t i o n ( JFrame . EXIT ON CLOSE ) ; s e t L a y o u t (new FlowLayout ( ) ) ; e t i q u e t a . s e t F o n t (new Font ( ” A r i a l ” , Font . ITALIC , 2 2 ) ) ; c a f e . addItemListener ( this ) ; cola . addItemListener ( this ) ; leche . addItemListener ( this ) ; agua . a d d I t e m L i s t e n e r ( t h i s ) ; add ( e t i q u e t a ) ; add ( c a f e ) ; add ( c o l a ) ; add ( l e c h e ) ; add ( agua ) ; add ( e s t a d o ) ; } public void itemStateChanged ( ItemEvent e ) { Object f u e n t e = e . g e t I t e m ( ) ; JCheckBox cb = ( JCheckBox ) f u e n t e ; int s e l e c c i o n = e . g e t S t a t e C h a n g e ( ) ; i f ( s e l e c c i o n == ItemEvent .SELECTED) e s t a d o . s e t T e x t ( ”¡Se ha s e l e c c i o n a d o ”+cb . getText ()+ ” ! ” ) ; else e s t a d o . s e t T e x t ( ”¡Se ha q u i t a d o l a s e l e c c i ´on ”+cb . getText ()+ ” ! ” ) ; } public s t a t i c void main ( S t r i n g [ ] arguments ) { f i n a l int FRAME WIDTH = 3 5 0 ; f i n a l int FRAME HEIGHT = 1 2 0 ; DemoCheckBox ventana = new DemoCheckBox ( ) ; ventana . s e t S i z e (FRAME WIDTH, FRAME HEIGHT ) ; ventana . s e t V i s i b l e ( true ) ; }

import import import public

5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

}

C´ odigo 13: Aplicaci´on DemoCheckBox. La jerarqu´ıa de herencia de la clase JCheckBox se muestra enseguida. Los m´etodos m´as frecuentemente usados aparacen en el cuadro 5. java.lang.Object | +--java.awt.Component 24

| +---java.awt.Container | +---javax.swing.JComponent | +---javax.swing.AbstractButton | +---javax.swing.JToggleButton | +---javax.swing.JCheckBox

M´ etodo void setText(String) String getText() void setSelected(boolean) boolean isSelected()

Prop´ osito pone el texto para el JCheckBox. regresa el texto JCheckBox. pone el estado del JCheckBox a true para seleccionado o false para no seleccionado. obtiene el estado actual (marcado o desmarcado) del JCheckBox.

Cuadro 5: M´etodos JCheckBox usados frecuentemente. Varios constructores pueden ser usados con JCheckBox. Cuando se construye un JCheckBox, se puede escoger si se le asigna una etiqueta; si el JCheckBox aparece seleccionado, por defecto un JCheckBox no est´ a seleccionado. Las siguientes sentencias crean cuatro objetos JCheckBox: Sin etiqueta y sin selecci´ on. JCheckBox casilla1 = new JCheckBox(); Con etiqueta y sin selecci´ on. JCheckBox casilla2 = new JCheckBox("Marcar aqu´ ı"); Con etiqueta y sin selecci´ on. JCheckBox casilla3 = new JCheckBox("Marcar aqu´ ı", false ); Con etiqueta y seleccionado. JCheckBox casilla4 = new JCheckBox("Marcar aqu´ ı", true ); Si no se quiere inicializar un JCheckBox con una etiqueta y se quiere asignar despu´es, o si se quiere cambiar una etiqueta existente, se puede usar el m´etodo setText(), como sigue: casilla1.setText("Marcar esta casilla ahora);

25

Se puede poner el estado de un JCheckBox con el m´etodo setSelected(); por ejemplo, se puede usar la siguiente sentencia para asegurar que casilla1 no est´e seleccionada: casilla1.setSelected(false ); El m´etodo isSelected() es m´ as u ´til en expresiones booleanas, como en el siguiente ejemplo, la cual agrega uno a una variable contadorVotos si casilla2 est´a actualmente marcada. if (casilla2.isSelected()) ++contadorVotos; Cuando el estado de un JCheckBox cambia de marcado a no marcado, o viceversa, un evento ItemEvent es generado, y el m´etodo itemStateChanged() es ejecutado. Se puede usar el m´etodo getItem() para determinar cual objeto gener´o el evento y m´etodo getStateChange() para determinar si el evento fue una selecci´ on o no. El m´etodo getStateChange() devuelve un entero que es igual a una de las dos constantes de clase—ItemEvent.SELECTED o ItemEvent.DESELECTED. En el siguiente extracto de c´odigo el m´etodo itemStateChanged() llama al m´etodo getItem(), el cual regresa el objeto llamado fuente. Luego, el valor de fuente es probado con una sentencia if para determinar si este es equivalente a un objeto JCheckBox llamado casilla. Si las dos referencias son al mismo objeto, el c´ odigo determina si la casilla fue seleccionada o no, y en cada caso las acciones apropiadas son hechas. public void itemStateChanged(ItemEvent e) { Object fuente = e.getItem(); if (fuente == casilla) { int seleccion = e.getStateChange(): if (seleccion == ItemEvent.SELECTED) // sentencias que se ejecutan cuando la casilla est´ a seleccionada else // sentencias que se ejecutan cuando la casilla NO est´ a seleccionada } else { // sentencias que se ejecutan cuando la fuente del evento es otro // componente diferente a casilla } }

Clase ButtonGroup Cuando se quieren opciones mutuamente exclusivas, es decir, se quiere que el usuario s´olo pueda seleccionar una opci´ on de varias, se debe crear un ButtonGroup para agrupar varios componentes, tales como los JCheckBox. Cuando se agrupan objetos JCheckBox y el usuario selecciona cualquiera de las casillas, el resto de las casillas queda sin selecci´on. La clase ButtonGroup desciende directamente de la clase Object y tambi´en es parte del paquete javax.swing. 26

Nota. Un grupo de JCheckBox en el cual un usuario puede seleccionar uno a la vez act´ ua como un conjunto de botones de radio, los cuales se pueden crear usando la clase JRadioButton. La clase JRadioButton es similar a la clase JCheckBox, y se debe preferir su uso cuando se tiene una lista de opciones de usuario mutuamente excluyente.

Para crear un ButtonGroup en un JFrame y luego agregar un JCheckBox, se deben realizar los siguientes cuatro pasos: 1. Crear un ButtonGroup, tal como: ButtonGroup unGrupo = new ButtonGroup(); 2. Crear un JCheckBox JCheckBox unaCasilla = new JCheckBox(); 3. Agregar unaCasilla a unGrupo unGrupo.add(unaCasilla); 4. Agregar unaCasilla al JFrame add(unaCasilla); Se puede crear un ButtonGroup y luego crear los objetos individuales JCheckBox, o tambi´en invirtiendo el orden. Si se crea un ButtonGroup pero se olvida agregar cualquier objeto JCheckBox a este, entonces los JCheckBox act´ uan como casillas individuales no exclusivas. Un usuario puede marcar uno de los JCheckBox de un grupo pulsando con el rat´on en este, o con c´odigo puede seleccionar un JCheckBox dentro de un ButtonGroup con una sentencia como la siguiente: unGrupo.setSelected(unaCasilla); Solo un JCheckBox puede ser seleccionado dentro de un grupo. Si se asigna el estado selected a un JCheckBox dentro de un grupo, cualquier asignaci´on previa es dejada sin marca. Se puede determinar cual, si hay, de los JCheckBox en un ButtonGroup est´a seleccionado con el m´etodo isSelected(). No se puede “limpiar la casilla” para todos los elementos que son miembros de un ButtonGroup. Se podr´ıa hacer que todos los JCheckBox en un ButtonGroup inicialmente se muestren sin selecci´ on agregando un JCheckBox que no sea visible, usando en este el m´etodo setVisible(). Luego, se podr´ıa usar el m´etodo setSelected() para marcar el JCheckBox no visible, y el resto se muestre sin marca.

27

Clase JComboBox Un JComboBox es un componente que combina dos caracter´ısticas: una ´area de visualizaci´on mostrando una opci´ on por defecto y un cuadro de lista que contiene opciones adicionales alternas. El ´area de visualizaci´ on contiene un bot´ on que el usuario puede pulsar o un campo editable en el cual el usuario puede teclear. Cuando un JComboBox se muestra, la opci´on por defecto es mostrada. Cuando el usuario pulsa el JComboBox, una lista de elementos alternativos cae; si el usuario selecciona alguno, este reemplaza el elemento del cuadro mostrado. Los usuario esperan ver las opciones de un JComboBox en orden alfab´etico. Otras formas razonables son poner las opciones en alg´ un otro orden l´ ogico, como “peque˜ no”, “mediano”, y “grande”, o poniendo a los m´as frecuentemente seleccionados primero. La jerarqu´ıa de herencia de la clase JComboBox se muestra a continuaci´on. java.lang.Object | +--java.awt.Component | +---java.awt.Container | +---javax.swing.JComponent | +---javax.swing.JComboBox Se puede construir un JComboBox usando un constructor sin argumentos y luego agregando elementos, por ejemplo, String a la lista con el m´etodo addItem(). Las siguientes sentencias crean un JComboBox llamado opcionPrincipal que contiene tres opciones de las cuales un usuario puede escoger: JComboBox opcionPrincipal = new JComboBox(); opcionPrincipal.addItem("Ingl´ es"); opcionPrincipal.addItem("Matem´ aticas"); opcionPrincipal.addItem("Sociolog´ ıa"); En la declaraci´ on del JComboBox del ejemplo previo, se usa seguido del nombre de la clase. Por defecto, un JComboBox espera elementos que los elementos agregados sean del tipo Object. Usando String encerrado entre par´entesis angulares se notifica al compilador que los elementos esperados en el JComboBox son String y se permite que el compilador revise por errores si elementos inv´alidos son agregados. Cuando no se indica un tipo de dato para un JComboBox, el programa compila, pero un mensaje de advertencia es marcado con cada llamada al m´etodo addItem(). Se dice que la clase JComboBox usa gen´ericos. La programaci´ on con gen´ ericos es una caracter´ıstica de los lenguajes modernos que permiten que tipos de datos m´ ultiples sean usados de forma segura con m´etodos. Otra forma de construir un JComboBox es usando un arreglo de Object como argumento para el constructor; los elementos en el arreglo se convierten en la lista de elementos dentro del JComboBox. El siguiente c´ odigo crea el mismo JComboBox opcionPrincipal como en el c´odigo precedente: 28

String[] arregloPrincipal = {"Ingl´ es","Matem´ aticas","Sociolog´ ıa"}; JComboBox opcionPrincipal = new JComboBox(arregloPrincipal); El cuadro 6 lista algunos m´etodos que se pueden usar con un objeto JComboBox. Por ejemplo, se puede usar el m´etodo setSelectedItem() o setSelectedIndex() para escoger uno de los elementos en un JComboBox para que sea el elemento seleccionado inicialmente. Se puede usar el m´etodo getSelectedItem() o getSelectedIndex() para saber cual elemento est´a actualmente seleccionado. M´ etodo void addItem(Object) void removeItem(Object) void removeAllItems() Object getItemAt(int) int getItemCount() int getMaximumRowCount()

int getSelectedIndex() Object getSelectedItem() Object[] getSelectedObjects() void setEditable(boolean) void setMaximumRowCount(int) void setSelectedIndex(int) void setSelectedItem(Object)

Prop´ osito Agrega un elemento a la lista. Quita un elemento de la lista. Quita todos los elementos de la lista. Regresa el elemento de la lista en la posici´on indicada por el ´ındice entero. Devuelve la cantidad de elementos en la lista. Regresa la cantidad m´axima de elementos que el cuadro lista puede desplegar sin una barra de desplazamiento. Da la posici´on del elemento seleccionado actualmente. Da el elemento seleccionado actualmente. Devuelve un arreglo conteniendo los Object seleccionados. Pone el campo para que sea editable o no. Pone la cantidad de renglones en el cuadro de lista que pueden ser mostrados a la vez. Pone el ´ındice en la posici´on indicada por el argumento. Pone el elemento seleccionado en el ´area de visualizaci´on.

Cuadro 6: M´etodos JComboBox usados frecuentemente. Se puede tratar una lista de elementos en un objeto JComboBox como un arreglo; el primer elemento est´a en la posici´ on cero, el segundo en la posici´on uno, etc. Es adecuado usar el m´etodo getSelectedIndex() para determinar la posici´on en la lista del elemento actualmente seleccionado; luego se puede usar el ´ındice para acceder la informaci´on correspondiente guardada en un arreglo paralelo. Por ejemplo, si un JComboBox llamado opcionesHistoria ha sido llenado con una lista de eventos hist´ oricos, tales como “Declaraci´on de Independencia”, “Batalla de Puebla”, y “Expropiaci´ on Petrolera” se puede codificar lo siguiente para recuperar la opci´on del usuario: int posicionSeleccion = opcionesHistoria.getSelectedIndex(); La variable posicionSeleccion guarda la posici´on del elemento seleccionado, y se puede usar la variable para acceder un arreglo de fechas para poder mostrar la fecha que corresponde al evento. Por ejemplo, si se declara lo siguiente, entondces fechas[posicionSeleccion] tiene el a˜ no para el evento hist´ orico seleccionado: 29

int fechas = {1810,1862,1938}; Nota. Un JComboBox no tiene que guardar los elementos declarados como String; puede guardar un arreglo de Object y mostrar los resultados del m´etodo toString() usados con esos objetos. Es decir, en vez de usar arreglos paralelos para guardar eventos hist´oricos y fechas, se podr´ıa designar una clase EventoHist´ orico que encapsule String para el evento e int para la fecha.

Adem´as de un JComboBox para el cual el usuario pulse sobre elementos presentados en una lista, se puede crear un JComboBox en el cual el usuario pueda teclear texto. Para hacer esto, se usa el m´etodo setEditable(). Una desventaja de usar un JComboBox es que el texto que el usuario ingresa debe ser exactamente igual a un elemento en el cuadro de lista. Si el usuario introduce incorrectamente la selecci´ on o el uso de may´ usculas/min´ usculas, no devuelve un valor v´alido la llamada del m´etodo getSelectedIndex(). Se puede usar una sentencia if para probar el valor regresado de getSelectedIndex(); si este es negativo, la selecci´on no aparea ning´ un elemento en el JComboBox, y se puede generar un mensaje de error apropiado. Actividad 5. Crea una aplicaci´ on interactiva para un hotel incluyendo JCheckBox para las diferentes selecciones. El precio base para un cuarto es $2000, y un hu´esped puede escoger de varias opciones. Reservar un cuarto para un fin de semana agrega $1000 al precio, incluir desayuno agrega $200, e incluir un viaje en lancha agrega $750. Un hu´esped puede seleccionar ninguna, alguna u todos estos servicios. Cada vez que el usuario cambia la opciones del paquete, el precio es recalculado.

30