Introducción a componentes Swing

Anuncio
Introducción a componentes Swing
H. Tejeda
Mayo 2016
Índice
1. Introducción
1
2. Clase JFrame
2
3. Clase JLabel
6
4. Manejador de diseño
9
5. Extensión de la clase JFrame
11
6. Clases de entrada
13
7. Programación de manejo de eventos
17
8. Receptores de eventos
21
9. Clases para selección
23
1.
Introducción
Las aplicaciones son más 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álogo y botones; se reconocen porque sus nombres inician con J.
Nota. Los componentes Swing fueron nombrados por un estilo musical que fue popular allá en 1940.
El nombre implica que los componentes tienen estilo y dinamismo. Las clases Swing son parte de un
1
conjunto más general de capacidades de programación UI que son llamadas las clases de fundación
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ñaron 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én 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étodos 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ón de las especificaciones del lenguaje Java original.
Nota. Casi todos los componentes Swing se dice que son componentes peso ligero porque están
escritos completamente en Java y no descansan en el código 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ás cercano peso pesado; un componente peso pesado tiene su propia ventana nativa
opaca. Los ú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án 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ás ú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
árbol de herencia de la clase JFrame para mostrar la relación 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ón, 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étodos ú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ño 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ños 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ño de un JFrame, no se tiene el área completa disponible para usarla porque
parte del área es usada por la barra de tı́tulo y los bordes del JFrame.
La aplicación JFrame1, código 1, muestra una aplicación que crea un JFrame pequeño y vacı́o.
3
Método
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ón
Pone el tı́tulo del JFrame usando el argumento
String.
Fija el tamaño de un JFrame en pı́xeles con el ancho
y alto como argumento.
Fija el tamaño 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étodo, 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étodos ú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ódigo 1: Aplicación JFrame1.
La aplicación JFrame1, código 1, crea un JFrame. Este se parece a marcos que se han visto cuando
se usan programas UI diferentes. La razón para usar objetos marco similares es porque los usuarios
ya están familiarizados con el ambiente de marcos. Cuando los usuarios ven marcos esperan ver una
barra de tı́tulo en la cima con información de texto. También 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ño 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ón del código 1, las tres sentencias en el método main() son importantes. Después de
instancia unMarco, se necesita hacer setVisible(true) para poder ver el JFrame, y también poner
su tamaño ya que de otra forma solo la barra de tı́tulo del JFrame es visible porque el tamaño de este
es 0 x 0 por defecto. Una razón por la cual el JFrame es invisible es porque este se podrı́a construir
en segundo plano mientras otras acciones están ocurriendo y quizás se desearı́a hacer visible más
tarde. Algunos programadores usan el método show() en vez del método setVisible().
Cuando un usuario cierra un JFrame pulsando en el botón cerrar en alguna de la esquinas superiores, el comportamiento por defecto para el JFrame es ocultarse y para la aplicación continuar
ejecutándose. Esto tiene sentido cuando hay otras tareas por completar para el programa después
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ón
de Swing se quiere que el programa termine cuando el usuario pulsa el botón cerrar. Para cambiar el
comportamiento se puede llamar al método 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ón la aplicación.
WindowConstants.DO NOTHING ON CLOSE mantiene el JFrame abierto y continúa ejecutándose. En otras palabras, deshabilita el botón cerrar.
WindowConstants.HIDE ON CLOSE cierra el JFrame y continúa ejecutándose; este es el comportamiento por defecto.
Cuando se ejecuta una aplicación en cual se ha olvidado salir cuando el JFrame es cerrado, se puede
terminar el programa tecleando CTRL+C.
5
Personalización de la apariencia de un JFrame
La apariencia de un JFrame es dada por el sistema operativo en el cual el programa esté ejecutándose. El diseño de los elementos que controlan el marco se parecen y se comportan como lo
hace cualquier otra aplicación gráfica. 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é 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étodo setDefaultLookAndFeelDecorated(). La aplicación JFrame2, código 2, hace una llamada a este método 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ódigo 2: La clase JFrame2.
Puede ser que al usar el método setDefaultLookAndFeelDecorated() el sistema operativo impida
modificar su apariencia, como en Mac OS X.
Actividad 1. Escribir una aplicación gráfica que muestre en el tı́tulo de la ventana su nombre y
tenga un tamaño cuadrado. Además la aplicación 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ónHorizontal) crea una instancia JLabel con la imagen especificada y la alineación horizontal.
JLabel(String texto) crea una instancia JLabel con el texto especificado.
JLabel(String texto, Icon imagen, int alineaciónHorizontal) crea una instancia JLabel con el texto, la imagen, y la alineación horizontal especificados.
JLabel(String texto, int alineaciónHorizontal) crea una instancia JLabel con el texto y la alineación 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étodo add() como
sigue:
unMarco.add(saludo);
La aplicación JFrame3, código 3, muestra la creación de JFrame al que enseguida se le pone su
tamaño y la operación 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ódigo 3: La clase JFrame3.
La contraparte del método add() es el método remove(). La siguiente sentencia quita saludo de
unMarco:
7
unMarco.remove(saludo);
Si se agrega, o quita un componente de un contenedor después de que este se hizo visible, se deberı́a
también llamar los métodos 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ño tomarán efecto. Los métodos 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ón, no se
tiene que llamar al método repaint() si después se modifica el componente, como por ejemplo,
cambiando el texto. Sólo se necesita llamar a repaint() si se agrega o quita un componente después
de la construcción.
Se puede cambiar el texto en un JLabel usando el método setText() de la clase Component con
el objeto JLabel y pasándole un String. El siguiente código 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étodo 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ón
del estilo y del tamaño de la fuente. El método setFont() requiere un argumento objeto Font.
Para construir un objeto Font, se necesitan tres argumentos: tipo de fuente, estilo, y tamaño 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ón; 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ño 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ón, el tamaño de punto define una medida entre lı́neas de texto en un documento de texto con interlineado simple. Java adopta la convención 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étodo setFont() para asignar el objeto Font al objeto JLabel con una sentencia
como la siguiente:
saludo.setFont(fuenteCabecera);
La aplicación JFrame4, código 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ño 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ódigo 4: La clase JFrame4.
No es obligatorio proporcionar un identificador para un objeto Font. Se pudo omitir la lı́nea 7 en el
código 4 y poner la fuente en saludo con la siguiente sentencia, la cual usa un objeto Font anónimo:
saludo.setFont(new Font("Arial", Font.BOLD, 36));
Después de crear un objeto Font, se puede crear un nuevo objeto con un tipo y tamaño diferente
usando el método deriveFont() con los argumentos apropiados. Por ejemplo, las siguientes dos
sentencias crean el objeto fuenteCabecera y el fuenteCuerpoTexto que está basado en el primer
objeto:
Font fuenteCabecera = new Font("Arial", Font.BOLD, 36);
Font fuenteCuerpoTexto = fuenteCabecera.deriveFont(Font.PLAIN, 14);
4.
Manejador de diseño
Cuando se quiere agregar múltiples componentes a un JFrame u otro contenedor, usualmente se requiere proporcionar instrucciones para la colocación de los componentes. En la aplicación JFrame5,
9
código 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én 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ódigo 5: La clase JFrame5.
Cuando se ejecuta la aplicación JFrame5 sólo la ú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ándola completamente. Si se continúan agregando más JLabel en el programa, sólo la última
agregada al JFrame será visible.
Para colocar múltiples 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ño, 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ón 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ón, y
cuando el renglón se llena, los componentes automáticamente se ponen en el siguiente renglón.
Tres constantes están definidas en la clase FlowLayout para indicar como los componentes son
posicionados en cada renglón de su contenedor. Estas son FlowLayout.LEFT, FlowLayout.RIGHT,
y FlowLayout.CENTER. Para crear un manejador de diseño 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ón.
Una vez que el manejador de diseño ha sido creado entonces puede ser puesto al objeto JFrame
haciendo lo siguiente:
unMarco.setLayout(flujo);
Se puede compactar el código usando un objeto FlowLayout anónimo con:
10
unMarco.setLayout(new FlowLayout(FlowLayout.RIGHT));
La aplicación JFrame6, código 6, ha puesto el manejador de diseño del JFrame para que componentes
múltiples 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én 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ódigo 6: La clase JFrame6.
Al ejecutar la aplicación JFrame6 se deben ver los dos JLabel, uno al lado del otro porque se usa
un FlowLayout. Si hubiera más JLabel u otros componentes, estos serı́an colocados continuamente
lado por lado a través del JFrame hasta que no haya más espacio.
5.
Extensión de la clase JFrame
Se puede instanciar un objeto JFrame simple dentro del método main() de una aplicación o en
cualquier otro método 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áticamente con las caracterı́sticas que
se hayan especificado, tales como el tamaño, el tı́tulo, y la operación 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á ser la primera sentencia en el constructor de la clase hija.
La clase JMiMarco, código 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én fija el tamaño, la operación de cierre por defecto y la visibilidad
para cada JMiMarco. Cada uno de los métodos—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ódigo 7: La clase JMiMarco.
Cuando se ejecuta la aplicación CrearDosObjetosMiMarco, código 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ódigo 8: La aplicación CrearDosObjetosMiMarco.
Nota. Se podrı́a usar el método 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étodo
setLocation() que se puede usar con un JFrame. Para usar este método, se deben dar valores para
las posiciones horizontal y vertical como argumentos del método.
Nota. Se termina la aplicación cuando se pulsa en el botón cerrar de alguno de los dos objetos
JMiMarco. Cada objeto tiene la misma operación de cierre por defecto porque cada uno usa el mismo
constructor que indica esa operación. Para permitir que sólo un JMiMarco controle la terminación
del programa, se podrı́a usar el método setDefaultCloseOperation() con alguno de los objetos
en la aplicación para cambiar su comportamiento de cierre, quizás usando DISPOSE ON CLOSE para
descartar uno de los marcos pero manteniendo la aplicación en ejecución.
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án 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ón usar el método 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á visible.
Nota. Algunos programadores ponen un método main() dentro de una clase como JMiMarco. Luego
la clase da la opción para ser usada para instanciar objetos, como en la aplicación CrearDosObjetosMiMarco,
o para ser usada ejecutándose como un programa que crea un objeto.
12
6.
Clases de entrada
Un JFrame también contiene otras caracterı́sticas de ventana, tales como JTextField, JButton, e
información 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ácter que se pueda meter del teclado o aplicación, incluyendo números y
signos de puntuación. 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ón con el ratón 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ás ancha que i, ası́ un JTextField de
tamaño 10 usando la fuente Arial puede mostrar 24 caracteres i, pero sólo 8 caracteres m.
Se debe intentar anticipar cuanto caracteres los usuarios podrı́an ingresar cuando se crea un
JTextField. El usuario puede meter más 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ño de un campo de texto.
Otros métodos están disponibles para ser usados con objetos JTextField. El método setText()
permite cambiar el texto en un JTextField, u otro Componet, que ha sido creado, como se muestra
enseguida:
respuesta.setText("Gracias");
Después 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étodo 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étodo 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ón para hacer una
selección. Hay cinco constructores JButton y son:
14
JButton() crea un botón sin texto.
JButton(Icon ı́cono) crea un botón con un ı́cono de tipo Icon o ImageIcon.
JButton(String texto) crea un botón con texto.
JButton(String texto, Icon icon) crea un botón con el texto inicial y un ı́cono del tipo
Icon o ImageIcon.
JButton(Action a) crea un botón 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é listo”, se puede escribir lo siguiente:
JButton botonListo = new JButton("Pulsar cuando esté listo");
Se puede agregar un JButton a un JFrame usando el método add(). Se puede cambiar la etiqueta
de un JButton con el método 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étodo getText(),
usando:
String queEstaEnJButton = botonListo.getText();
La clase JFrameConMuchosComponentes, código 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ódigo 9: La clase JFrameConMuchosComponentes.
La aplicación DemoComponentes, código 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ódigo 10: Aplicación DemoComponentes.
Al ejecutar la aplicación 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ño arrastrando los bordes del marco. El usuario puede teclea en el JTextField
y pulsar el JButton. Cuando el botón 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ón,
no ocurren acciones resultantes porque no se ha sido escrito todavı́a código para manejar es eventos
iniciados por usuario.
Uso de información sobre herramientas
Información sobre herramientas (tool tips) son ventanas emergentes que pueden ayudar al
usuario a entender el propósito de los componentes en una aplicación; la información aparece cuando
un usuario flota el apuntador del ratón encima del componente. Se define el texto que será mostrado
en una sugerencia usando el método setToolTipText() y pasándole un String apropiado. En
la clase JFrameConMuchosComponentes, código 9, se puede agregar una sugerencia al componente
16
boton usando la siguiente sentencia en el constructor JFrame:
boton.setToolTipText("Pulsa este botón");
Actividad 2. Crear una aplicación Swing que muestre un JFrame que tenga un JLabel, un
JTextField, y un JButton. El diseño de esta aplicación deberá incluir una clase que extienda
a la clase JFrame, la cual tendrá los componentes como campos de esta clase con la correspondiente asignación de los objetos instanciados; en el constructor de la clase hija configurar el marco y
agregar los componentes. Luego escribir una aplicación que cree un objeto de la clase hija donde se
deberá fijar el tamaño de la ventana en 350 de ancho y 100 de alto usando constantes.
7.
Programación de manejo de eventos
Un evento ocurre cuando un usuario realiza una acción en un componente, tal como pulsar el
ratón 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ón, pulsar un botón para cambiar el texto a negritas, o a itálicas, escoger un
elemento del menú, etc. Con cada documento creado se escogen opciones en el orden que parece
más apropiado en el momento. El programa procesador de textos deberá 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ón 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á 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 áreas 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ón, 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ón en su superficie. Cuando un receptor “recibe las noticias”, un método 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án.
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ón del botón 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étodos que se pueden usar. Implementar ActionListener da especificaciones estándar de
métodos de eventos que permiten al receptor trabajar con ActionEvent, el cual es el tipo de evento
que ocurre cuando se pulsa un botón.
Indicar a la clase para que espere eventos que pasarán
Se le dice a una clase que espere eventos ActionEvent con el método addActionListener().
Si se ha declarado un JButton llamado unBoton, y se quiere realizar una acción 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ódigo unBoton.addActionListener(this); hace que cualquier mensaje ActionEvent (pulsar botón)
que venga de unBoton sea enviado a “este objeto actual”.
Nota. No todos los eventos son ActionEvent con un método addActionListener(). Por ejemplo,
KeyListener tiene un método addKeyListener, y FocusListener tiene un método addFocusListener.
Indicar a la clase como responder a los eventos
La interfaz ActionListener contiene la especificación del método 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étodo actionPerformed() se ejecuta.
Se implementa el método actionPerformed() usando la siguiente cabecera, donde e representa
cualquier nombre que se quiera para el evento que inició la notificación al ActionListener, el cual
es el JFrame:
public void actionPerformed(ActionEvent e)
El cuerpo del método contiene cualquier sentencia que se quiera ejecutar cuando la acción ocurre. Se
podrı́a querer realizar un cálculo matemático, construir nuevos objetos, generar salida, o ejecutar
cualquier otra operación. En la clase JVentanaHola, código 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étodo actionPerformed() se ejecuta cuando el usuario pulsa el botón JButton; dentro del
método, 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á 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ódigo 11: La clase JVentanaHola.
La aplicación JDemoHola, código 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ódigo 12: Aplicación JDemoHola.
Cuando se ejecuta la aplicación JDemoHola, la cual instancia un objeto JVentanaHola, después de
que el usuario ingresa un nombre, el programa lo saluda con el nombre después de que el usuario
pulsa el botón.
Cuando más 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ódigo
jventanahola, se podrı́a querer que el usuario pueda ver el mensaje después de pulsar el botón 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étodo 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ólo método actionPerformed(), ası́ que este es el método que se ejecuta cuando el botón 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étodo actionPerformed(), se puede usar el método
getSource() del objeto enviado para determinar cual componente generó el evento. Por ejemplo,
dentro de un método 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ó 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ón en el siguiente método para tomar diferentes acciones dependiendo del botón
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én usar la palabra reservada instanceof para determinar la
fuente del evento. instanceof es usada cuando es necesario conocer sólo el tipo del componente,
en vez del componente que disparó el evento. Por ejemplo, si se quiere tomar alguna acción 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étodo 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étodo 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án habilitados por defecto, pero se puede
usar el método 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ón o presionar la tecla Intro se deberá cambiar el texto de la etiqueta para que muestre un
mensaje de agradecimiento y para que el botón muestre la cadena “Hecho”.
Actividad 4. Repetir la actividad anterior pero ahora sólo se modificará el texto de la etiqueta
para que indique quien fue la fuente del evento, si el botón 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ón de un botón del ratón y a un teclazo, ası́ que se deberán
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ón
Eventos de ajuste
ChangeListener
FocusListener
Eventos de cambio
Eventos del foco del teclado
ItemListener
Eventos de elementos
KeyListener
MouseListener
MouseMotionListener
Eventos
Eventos
Eventos
ratón
Eventos
WindowListener
del teclado
del ratón
de movimiento del
Ejemplo
Pulsar botón
Mover barra de desplazamiento
Reposicionar deslizador
Gana o pierde el foco un
campo de texto
Cambiar estado de casilla
de verificación
Ingresar texto
Pulsar botón del ratón
Mover ratón
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ón del ratón. 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ón 6, se ha
mostrado como establecer una relación entre un JButton y un JFrame que lo contiene usando el
método 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á asociado con un método de la columna derecha.
21
Por ejemplo, cuando se quiere que un JCheckBox responda a las pulsaciones del usuario, se puede
usar el método 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éntesis de la llamda al
método addItemListener() es el objeto que deberı́a responder al evento—quizás un JFrame que
contiene el JCheckBox generador del evento. El formato es:
laFuenteDelEvento.addListenerMetodo(laClaseQueDeberáResponder);
Componente(s)
Método(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étodos registradores-receptores asociados
Nota. Cualquier fuente de eventos puede tener múltipes 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étodo que acepte el objeto evento
creado por la acción del usuario. Un método que se ejecuta porque es llamado automáticamente
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étodo manejador de evento. No se puede escoger un
nombre propio para los manejadores de evento—identificadores de métodos especı́ficos reaccionan
a tipos especı́ficos de eventos. En el cuadro 4 se listan algunos de los métodos que reaccionan a
eventos.
Receptor
ActionListener
AdjustmentListener
FocusListener
ItemListener
Método
actionPerformed(ActionEvent)
adjustmentValueChanged(AdjustmentEvent)
focusGained(FocusEvent)
y
focusLost(FocusEvent)
itemStateChanged(ItemEvent)
Cuadro 4: Métodos 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á 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és se declara una clase que extienda MiMarco, no se necesita incluir implements
ItemListener en su cabecera. La nueva clase hereda la implementación.
Se debe registrar cada instancia de la clase manejadora de eventos como un receptor para uno
o más 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á declarado—en este caso, MiMarco.
Se debe escribir un método 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ón
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ón 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ón. La aplicación DemoCheckBox, código 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é d e s e a s tomar ? ” ) ;
JCheckBox c a f e = new JCheckBox ( ” Café” , 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ón 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 ón ”+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ódigo 13: Aplicación DemoCheckBox.
La jerarquı́a de herencia de la clase JCheckBox se muestra enseguida. Los métodos más 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étodo
void setText(String)
String getText()
void setSelected(boolean)
boolean isSelected()
Propósito
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étodos 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á seleccionado. Las siguientes sentencias crean cuatro objetos JCheckBox:
Sin etiqueta y sin selección.
JCheckBox casilla1 = new JCheckBox();
Con etiqueta y sin selección.
JCheckBox casilla2 = new JCheckBox("Marcar aquı́");
Con etiqueta y sin selección.
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és, o si se quiere
cambiar una etiqueta existente, se puede usar el método setText(), como sigue:
casilla1.setText("Marcar esta casilla ahora);
25
Se puede poner el estado de un JCheckBox con el método setSelected(); por ejemplo, se puede
usar la siguiente sentencia para asegurar que casilla1 no esté seleccionada:
casilla1.setSelected(false );
El método isSelected() es más útil en expresiones booleanas, como en el siguiente ejemplo, la
cual agrega uno a una variable contadorVotos si casilla2 está 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étodo itemStateChanged() es ejecutado. Se puede usar el método getItem() para determinar cual objeto generó el evento y método getStateChange() para
determinar si el evento fue una selección o no.
El método 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ódigo el método itemStateChanged() llama al método 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ódigo
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á seleccionada
else
// sentencias que se ejecutan cuando la casilla NO está 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ólo pueda
seleccionar una opción 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ón. La clase ButtonGroup desciende
directamente de la clase Object y también es parte del paquete javax.swing.
26
Nota. Un grupo de JCheckBox en el cual un usuario puede seleccionar uno a la vez actúa 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én invirtiendo el orden. Si se crea un ButtonGroup pero se olvida agregar cualquier objeto JCheckBox a
este, entonces los JCheckBox actúan como casillas individuales no exclusivas.
Un usuario puede marcar uno de los JCheckBox de un grupo pulsando con el ratón en este, o
con código 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ón previa es dejada sin marca.
Se puede determinar cual, si hay, de los JCheckBox en un ButtonGroup está seleccionado con el
método 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ón
agregando un JCheckBox que no sea visible, usando en este el método setVisible(). Luego, se
podrı́a usar el método 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 área de visualización mostrando una opción por defecto y un cuadro de lista que contiene opciones adicionales alternas. El
área de visualización contiene un botón que el usuario puede pulsar o un campo editable en el cual
el usuario puede teclear. Cuando un JComboBox se muestra, la opción 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ético. Otras formas razonables son poner las opciones en algún
otro orden lógico, como “pequeño”, “mediano”, y “grande”, o poniendo a los más frecuentemente
seleccionados primero.
La jerarquı́a de herencia de la clase JComboBox se muestra a continuación.
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étodo addItem(). Las siguientes sentencias crean un
JComboBox llamado opcionPrincipal que contiene tres opciones de las cuales un usuario puede
escoger:
JComboBox<String> opcionPrincipal = new JComboBox<String>();
opcionPrincipal.addItem("Inglés");
opcionPrincipal.addItem("Matemáticas");
opcionPrincipal.addItem("Sociologı́a");
En la declaración del JComboBox del ejemplo previo, se usa <String> 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éntesis 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álidos 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étodo addItem(). Se
dice que la clase JComboBox usa genéricos. La programación con genéricos es una caracterı́stica
de los lenguajes modernos que permiten que tipos de datos múltiples sean usados de forma segura
con métodos.
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ódigo crea el mismo JComboBox opcionPrincipal como en el código precedente:
28
String[] arregloPrincipal = {"Inglés","Matemáticas","Sociologı́a"};
JComboBox opcionPrincipal = new JComboBox(arregloPrincipal);
El cuadro 6 lista algunos métodos que se pueden usar con un objeto JComboBox. Por ejemplo,
se puede usar el método setSelectedItem() o setSelectedIndex() para escoger uno de los
elementos en un JComboBox para que sea el elemento seleccionado inicialmente. Se puede usar el
método getSelectedItem() o getSelectedIndex() para saber cual elemento está actualmente
seleccionado.
Método
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ósito
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ón indicada por el ı́ndice entero.
Devuelve la cantidad de elementos en la lista.
Regresa la cantidad máxima de elementos que el
cuadro lista puede desplegar sin una barra de desplazamiento.
Da la posición 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ón indicada por el argumento.
Pone el elemento seleccionado en el área de visualización.
Cuadro 6: Métodos JComboBox usados frecuentemente.
Se puede tratar una lista de elementos en un objeto JComboBox como un arreglo; el primer elemento está en la posición cero, el segundo en la posición uno, etc. Es adecuado usar el método
getSelectedIndex() para determinar la posición en la lista del elemento actualmente seleccionado; luego se puede usar el ı́ndice para acceder la información correspondiente guardada en un
arreglo paralelo. Por ejemplo, si un JComboBox llamado opcionesHistoria ha sido llenado con
una lista de eventos históricos, tales como “Declaración de Independencia”, “Batalla de Puebla”,
y “Expropiación Petrolera” se puede codificar lo siguiente para recuperar la opción del usuario:
int posicionSeleccion = opcionesHistoria.getSelectedIndex();
La variable posicionSeleccion guarda la posición 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ño para
el evento histórico 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étodo toString() usados con esos objetos. Es
decir, en vez de usar arreglos paralelos para guardar eventos históricos y fechas, se podrı́a designar
una clase EventoHistórico que encapsule String para el evento e int para la fecha.
Además 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étodo 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ón o el uso de mayúsculas/minúsculas, no devuelve un valor válido la
llamada del método getSelectedIndex(). Se puede usar una sentencia if para probar el valor
regresado de getSelectedIndex(); si este es negativo, la selección no aparea ningún elemento en
el JComboBox, y se puede generar un mensaje de error apropiado.
Actividad 5. Crea una aplicación interactiva para un hotel incluyendo JCheckBox para las diferentes selecciones. El precio base para un cuarto es $2000, y un huésped 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ésped puede seleccionar ninguna, alguna u
todos estos servicios. Cada vez que el usuario cambia la opciones del paquete, el precio es recalculado.
30
Documentos relacionados
Descargar