10 Curso de Java OO. Swing I
Resumen : Se estudiara el modelo de pantallas en SWING
1. SWING
- Es un conjunto de componentes visuales que son parte del java.
- Son livianos respecto a sus antecesores llamados AWT
- Son independientes de la plataforma.
- El siguiente es un árbol de componentes usados en SWING
- SWING usa la infraestructura de AWT
- A continuación se muestra los componentes visuales.
Componentes de alto nivel para Ventanas
JFrame
JDialog
JApplet
JWindow
JInternalFrame
Contenedor de componentes
JPanel
JScrollPane
JToolBar
JSplitPane
JTabbedPane
JDesktopPane
Componentes de menu
JMenuBar
JMenu
JCheckboxMenuItem
JPopupMenu
JMenuItem
JRadioButtonMenuItem
Componentes de texto
JTextField
JTextPane
JPasswordField
JEditorPane
JTextArea
JFormattedTextField
Componentes de complejos
JTable
JTree
JFileChooser
JList
JOptionPane
JColorChooser
Controles atomicos
JLabel
JButton
JToggleButton
JCheckBox
JRadioButton
JProgressBar
JSpinner
JComboBox
JSlider
JScrollBar
JSeparator
JToolTip
- La siguiente imagen corresponde a una aplicación creada con SWING
2. EL PRIMER PROGRAMA CON SWING
- Este es un ejemplo de las características básicas de una aplicación con SWING.
- Cada programa es SWING esta dividido en:
1. import de paquetes gráficos
2. Configurar el contenedor de alto nivel
3. Mostrar el contenedor
4. Asegurar consistencia del programa. (thread-safe)
2.1. import de paquetes gráficos
- La primera línea incorpora el SWING en el programa
import javax.swing.*;
- En la mayoría de programas se requiere importar además paquetes AWT.
- Estos paquetes se requieren porque SWING usa la infraestructura AWT.
- También usa los eventos AWT.
- Un evento es una acción sobre la aplicación. (presionar un botón, seleccionar un menú...)
import java.awt.*;
import java.awt.event.*;
2.2. Configurar el contenedor de alto nivel
- Cada programa Swing debe tener al menos un contenedor de alto nivel
- Un contenedor de alto nivel muestra y maneja los eventos de sus componentes.
- Se cuenta con tres contenedores de alto nivel: JApplet, JFrame, JDialog.
- JFrame implementa la ventana principal de la aplicación.
- JDialog implementa las ventanas secundarias generadas por otras ventanas.
- JApplet implementa un applet en un browser.
- JFrame implementa los elementos por defecto de una ventana como bordes, titulo, cambio de tamaño, botón para inconizar y cerrar. Estos elementos se llaman decorators. (versión 1.4)
JFrame.setDefaultLookAndFeelDecorated(true);
- La variable frame es un objeto de clase JFrame
- El siguiente código define el contenedor principal.
JFrame frame = new JFrame("HelloWorldSwing");
- Los contenedores de alto nivel (como JFrame) heredan de java.awt.Window
- Los componentes de los contenedores heredan de javax.swing.Jcomponent
- El programa usa un JComponent llamado Jlabel que muestra un texto.
- Estas líneas crean el componente JLabel y lo agregan al contenedor JFrame
JLabel label = new JLabel("Hello World");
frame.getContentPane().add(label);
- El JLabel no se agrega directamente al JFrame, sino a la zona de contenidos (contentPane)
- Todos los contenedores de alto nivel tienen una zona de contenidos
- Los componentes de la ventana se encuentran en esta zona
- No se encuentran en esta zona los menús ni los decorators.
- En la versión 1.5 se evitara la complejidad del contentPane y se podrá utilizar directamente el frame.
- Para que el programa termine al presionar el botón Close se requiere:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
2.3. Mostrar el contenedor.
- Para mostrar el contenedor se realiza lo siguiente:
frame.pack();
frame.setVisible(true);
- la primera línea coloca el tamaño de la ventana de acuerdo a sus componentes.
2.4. Asegurar la consistencia.
- Este código asegura que la ventana no se cuelgue antes de mostrarse en pantalla.
javax.swing.SwingUtilities.invokeLater
( new Runnable() {
public void run() { crearMostrarVentana(); }
}
);
2.5. Laboratorio
Modifique el programa cambiando los mensajes del programa. Pruebe los botones de la ventana.
TestSwing.java
import javax.swing.*;
public class TestSwing {
public static void main(String[] args) {
//Enviar una tarea al administrador de eventos
//para que cree y muestre la ventana
javax.swing.SwingUtilities.invokeLater
( new Runnable() {
public void run() { crearMostrarVentana(); }
}
);
}
// Metodo para crear una ventana.
private static void crearMostrarVentana() {
//Asegurarse que contenga los decorators de una ventana.
JFrame.setDefaultLookAndFeelDecorated(true);
//Crear y configurar la ventana
JFrame frame = new JFrame("TestSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Agregar un label que muestre "Hola Mundo!"
JLabel label = new JLabel("Hola Mundo!");
frame.getContentPane().add(label);
//Mostrar la ventana
frame.pack();
frame.setVisible(true);
}
}
3. UNA APLICACIÓN EN SWING
En la aplicación cada vez que se presione el botón, el contador de clicks se incrementara.
La aplicación explicara lo siguiente:
- Look and Feel
- Configurar de botones y labels
- Agregar componentes al contenedor
- Agregar bordes a los componentes
- Manejar los eventos.
3.1. Look and Feel
- Las pantallas muestran el look & feel posibles en la aplicación.
- Swing te permite indicar que apariencia (look and feel o LAF) se usara al mostrar la aplicación con la clase UIManager (administrador de la interfase de usuario).
- El código muestra como se define el look and feel por propio del Java (javax.swing.plaf.metal.MetalLookAndFeel)
Metal
Clase LAF usada : javax.swing.plaf.metal.MetalLookAndFeel
System
Motif
G
TK+
public class SwingMain {
//Indicar que look and feel se usara en la aplicacion.
//Los valores de LOOKANDFEEL seran:
// null (por defecto), "Metal", "System", "Motif" y "GTK+"
final static String LOOKANDFEEL = "Metal";
private static void initLookAndFeel() {
// Clase java que administrara el LAF.
String claseLAF = null;
if (LOOKANDFEEL.equals("Metal")) {
// retorna la clase del LAF propio del Java
claseLAF = UIManager.getCrossPlatformLookAndFeelClassName();
}
// UIManager es el administrador LAF
// el metodo configura el LAF de la aplicación
UIManager.setLookAndFeel(lookAndFeel);
}
}
3.2. Configurar botones y labels
- La mayoría de aplicaciones GUI presentan botones y labels (etiquetas)
- Este es el código que crea un label y un botón
- Adicionalmente se define una tecla rapida para el botón como ALT+S, con el fin de presionar el botón mediante el teclado
- También se agrega un manejador de eventos que se invocara cada vez que se presione el botón.
- El método setLabelFor indica a que componente (boton) etiqueta el label.
public class SwingContent {
private JButton boton;
private JLabel label;
public Component crearComponentes() {
//Creando los componentes de la ventana
label = new JLabel("Soy un label Swing!");
boton = new JButton("Soy un boton Swing!");
//Se agrega una tecla rapida ALT+S
boton.setMnemonic(KeyEvent.VK_S);
//Se agrega un manejador de eventos
SwingListener listener = new SwingListener();
boton.addActionListener(listener);
//Opcionalmente se enlaza el label al boton
label.setLabelFor(boton);
}
}
3.3. Agregar componentes al contenedor
- La aplicación crea un contenedor JPanel agrupando el label y el boton.
- Con el siguiente código se define el contenedor.
- Primero se crea el contenedor y se le asigna un layout manager (administrador de distribución de componentes)
- El layout manager determina el tamaño y posición de los componentes del contenedor.
- El código new GridLayout(0,1) fuerza a que los componentes se encuentren en una sola columna y con el mismo tamaño.
- Se agrega luego el label y el botón al panel
public class SwingContent {
public Component crearComponentes() {
//Se crea un layout para los componentes
LayoutManager layout = new GridLayout(0, 1);
JPanel panel = new JPanel(layout);
//Se agrega los componentes al panel.
panel.add(boton);
panel.add(label);
}
}
3.4. Agregar bordes a los componentes
- Si observa la ventana de la aplicación notara que existe un espacio vacio en el panel en sus 4 lados.
- Este código crea un espacio vacio alrededor de los componentes del contenedor.
- 30 pixeles hacia arriba, derecha e izquierda y 10 pixeles hacia abajo.
- El borde es un atributo que JPanel hereda de JComponent.
- El borde no es un componente, sino sirve para espaciar componentes.
public class SwingContent {
public Component crearComponentes() {
//Se agrega un borde vacio alrededor de los componentes.
panel.setBorder(BorderFactory.createEmptyBorder(
30, //arriba
30, //izquierda
10, //abajo
30) //derecha
);
return panel;
}
}
3.5. Manejar los eventos.
- Cada vez se tipea una tecla, se presiona el mouse; ocurre un evento.
- Cualquier objeto puede ser notificado por este evento.
- Los objetos con comportamiento, deben implementar manejador de eventos.
- En el ejemplo se ha declarado una clase interna para que maneje los eventos del botón.
public class SwingContent {
private int numClicks = 0;
private JLabel label;
public Component crearComponentes() {
//Se agrega un manejador de eventos
SwingListener listener = new SwingListener();
boton.addActionListener(listener);
}
//Clase interna que es un listener de eventos.
public class SwingListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
numClicks++;
label.setText("Cantidad de clicks : " + numClicks);
}
}
}
- Cada manejador de eventos requiere de 3 piezas de código.
3.5.1. Donde se manejaran los eventos?
Una clase que implementara el listener de eventos.
public class SwingListener implements ActionListener...
3.5.2. Que componentes tendran eventos?
Una declaracion que registra el listener como manejador de eventos de un componente.
SwingListener listener = new SwingListener();
boton.addActionListener(listener);
3.5.3. Que se realizara ante un evento?
Un método manejador de eventos que implementa la interfase del listener.
public void actionPerformed(ActionEvent e) {
numClicks++;
label.setText("Cantidad de clicks : " + numClicks);
}
- En general cuando el usuario presiona un boton en pantalla (o realiza su equivalente en teclado) el programa debe contar con un objeto que implemente la interfase ActionListener
- El programa debe registrar este objeto en la fuente del evento (el boton)
- Cuando el usuario presiona el boton, se realiza el evento, invocandose el método actionPerformed del ActionListener registrado.
3.6. LABORATORIO
- Pruebe el siguiente programa.
- Pruebe cada uno de los LOOKANDFEEL del programa. Que clase usan?
- Agregue un segundo boton (boton2) y un segundo label (label2) al programa pero cuyo contador (numClicks2) inicie en 1000 y se decremente con cada clic al boton2.
- Modifique el layout del contenedor:
LayoutManager layout = new GridLayout(0, 2);
LayoutManager layout = new FlowLayout();
SwingMain.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SwingMain {
//Indicar que look and feel se usara en la aplicacion.
//Los valores de LOOKANDFEEL seran:
// null (por defecto), "Metal", "System", "Motif" y "GTK+"
final static String LOOKANDFEEL = "Metal";
public static void main(String[] args) {
//Enviar una tarea al administrador de eventos
//para que cree y muestre la ventana
SwingUtilities.invokeLater
( new Runnable() {
public void run() { crearMostrarVentana(); }
}
);
}
// Metodo para crear una ventana GUI.
private static void crearMostrarVentana() {
//Configura el LAF.
iniciarLookAndFeel();
//Asegurarse que contenga los decorators de una ventana.
JFrame.setDefaultLookAndFeelDecorated(true);
//Crear y configurar la ventana
JFrame frame = new JFrame("SwingMain");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Agregar un panel que contiene un label y un boton
SwingContent contenido = new SwingContent();
Component panel = contenido.crearComponentes();
frame.getContentPane().add(panel);
//Mostrar la ventana
frame.pack();
frame.setVisible(true);
}
private static void iniciarLookAndFeel() {
// Clase java que administra el LAF.
String claseLAF = null;
if (LOOKANDFEEL != null) {
if (LOOKANDFEEL.equals("Metal")) {
// retorna la clase del LAF propio del Java
claseLAF = UIManager.getCrossPlatformLookAndFeelClassName();
} else if (LOOKANDFEEL.equals("System")) {
// retorna la clase del LAF de windows
claseLAF = UIManager.getSystemLookAndFeelClassName();
} else if (LOOKANDFEEL.equals("Motif")) {
claseLAF = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
} else if (LOOKANDFEEL.equals("GTK+")) {
claseLAF = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
} else {
System.err.println("Ha indicado un LOOKANDFEEL incorrecto : "
+ LOOKANDFEEL);
claseLAF = UIManager.getCrossPlatformLookAndFeelClassName();
}
System.out.println("Clase LAF usada : "+claseLAF);
try {
// UIManager es el administrador LAF
// el metodo configura el LAF de la aplicacion
UIManager.setLookAndFeel(claseLAF);
} catch (ClassNotFoundException e) {
System.err.println("No se encontro la clase para el LAF:"
+ claseLAF);
System.err.println("Ha incluido la libreria en classpath?");
System.err.println("Se usara LAF por defecto.");
} catch (UnsupportedLookAndFeelException e) {
System.err.println("No se puede usar el LAF indicado ("
+ claseLAF
+ ") en esta plataforma.");
System.err.println("Se usara LAF por defecto.");
} catch (Exception e) {
System.err.println("Se tiene problemas al usar el LAF ("
+ claseLAF
+ ")");
System.err.println("Se usara LAF por defecto.");
e.printStackTrace();
}
}
}
}
SwingContent.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SwingContent {
//Contador de clicks en el boton.
private int numClicks = 0;
//Componentes de la aplicacion.
private JButton boton;
private JLabel label;
public Component crearComponentes() {
//Creando los componentes de la ventana
label = new JLabel("Soy un label Swing!");
boton = new JButton("Soy un boton Swing!");
//Se agrega una tecla rapida ALT+S
boton.setMnemonic(KeyEvent.VK_S);
//Se agrega un manejador de eventos
BotonListener listener = new BotonListener();
boton.addActionListener(listener);
//Opcionalmente se enlaza el label al boton
label.setLabelFor(boton);
//Se crea un layout para los componentes
LayoutManager layout = new GridLayout(0, 1);
JPanel panel = new JPanel(layout);
//Se agrega los componentes al panel.
panel.add(boton);
panel.add(label);
//Se agrega un borde vacio alrededor de los componentes.
panel.setBorder(BorderFactory.createEmptyBorder(
30, //arriba
30, //izquierda
10, //abajo
30) //derecha
);
return panel;
}
//Clase interna que es un listener de eventos.
public class BotonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
numClicks++;
label.setText("Cantidad de clicks : " + numClicks);
}
}
}