Acciones en Java: mostrar fotos desde botones

Mostrar imágenes al pulsar botones en una ventana JFrame que implementa la interfaz ActionListener, detectar la pulsación del botón como un evento de acción (ActionEvent) y llamar a la acción prevista con el método actionPerformed,en Java

Introducción: responder a las acciones del usuario

Las aplicaciones han de responder a las acciones que realiza el usuario, por ejemplo: cerrar la ventana al pulsar un botón. Es necesario poder detectar las acciones de usuario y convertirlas en acciones de programa. Java dispone de varias formas de implementar este funcionamiento. En este ejercicio se mostrarán algunas de ellas. Todas se basan en el uso de Interfaces. Las Interfaces son clases “prefabricadas” con propósitos definidos
Cada Interface contiene declaraciones de métodos (nombre del método, lista de argumentos y tipo de retorno) pero estos métodos no están implementados (carecen de cuerpo) y deben ser desarrollados. Todos los métodos de las Interfaces son public. Las Interfaces también pueden declarar constantes (public final static).
En Java no existe la herencia múltiple como tal: una clase no puede heredar (extends) de más de una clase. Pero una clase puede implementar más de una Interface, ésta es una manera de tener herencia múltiple. En la clase que implementa una Interface han de ser sobrescritos (override) todos los métodos declarados en la Interface.

Respecto a la interfaz ActionListener:

  • ActionListener es una Interface del grupo de los Listeners
  • ActionListener tiene un sólo método: void actionPerformed(ActionEvent e)
  • ActionListener se usa para detectar y manejar eventos de acción (ActionEvent) que son los que tienen lugar cuando se produce una acción sobre un elemento del programa.

Un evento ActionEvent se produce:

  • al pulsar un botón (Button)
  • al hacer doble clic en un elemento de lista (List)
  • al pulsar INTRO en una caja de texto (TextField)
  • al elegir un menú (MenuItem).

Los distintos elementos del programa (botones, etc.) están  vigilados por Listeners que detectan las acciones que tienen lugar sobre el elemento supervisado. De manera que cuando el usuario pulsa un botón:

  • el botón sobre el que se produce una acción y genera un evento (event source, este dato se puede obtener con el método getSource) ha de estar previamente registrado con algún objeto que gestione el evento (ActionListener en este caso) mediante el método:
Button.addActionListener(this)
// o tambien
Button.addActionListener(ActionListener nombre_de_actionListener)

el botón genera un ActionEvent (clase del paquete java.awt.event)

ActionEvent invoca al método actionPerformed que realiza las acciones programadas

si la clase implementa ActionListener, ha de ser sobrescrito (override) el método public void actionPerformed(ActionEvent e).

Código principal del programa

Hay que importar estos paquetes e instanciar la clase principal:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.Color;
import java.net.URL;

// CLASE PRINCIPAL
public class Botones_fotos extends JFrame implements ActionListener

Un objeto JPanel derivado de la clase Container va a contener el resto de objetos de la ventana. Container es un componente genérico AWT que puede contener otros componentes AWT. Swing proporciona 2 contenedores de primer nivel: JFrame y JDialog, cada uno de ellos contiene un panel principal o raíz (JRootPane) con varios elementos:

  • panel de contenido (contentPane): los componentes visibles del contenedor de primer nivel, excepto barra de menú; por defecto tienen BorderLayout()
  • barra de menú (menuBar): es opcional, fuera de contentPane
  • panel de cristal (glassPane): por encima de menuBar y contentPane, oculto por defecto, se encarga de interceptar acciones del usuario para JRootPane.

No se pueden agregar elementos directamente a JRootPane. Hay que agregarlos al contentPane de rootPane con el método getContentPane():

rootPane.add(elemento); // NO
rootPane.getContentPane().add(elemento); // SI

Para agregar elementos a un Frame:

Frame.getContentPane().add(elemento);

El método getContentPane() devuelve un objeto Container, no un objeto JComponent, por ello es conveniente crear un componente personalizado para usar como contentPane. Para usar un componente como contentPane hay que:

// crear un panel y agregar componentes
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(elegirBorde);
panel.add(unComponente, BorderLayout.CENTER);
panel.add(otroComponente, BorderLayout.PAGE_END);
// hacer que panel sea contentPane de un contenedor de nivel superior
panel.setOpaque(true);
topLevelContainer.setContentPane(panel);

Se crean los diferentes paneles contenedores.

// panel1 es el contenedor de todos los elementos de la ventana
private JPanel panel1 = new JPanel(new BorderLayout());
// panel para la etiqueta rutaLabel y pBotones
private JPanel panelSup = new JPanel(new GridLayout(2,0));
// panel que agrupa los botones superiores
private JPanel pBotones = new JPanel(new GridLayout(1,0));
// panel para la etiqueta rutaLabel
private JPanel pLabel = new JPanel();
// panel para los botones inferiores
private JPanel pBotones2 = new JPanel(new GridLayout(1,0));

Se crean botones y etiquetas y se configura el tipo de letra.

// Array de botones con el nombre de la imagen en cada uno de ellos
private JButton[] strBotones =  {new JButton("Pelosas"), 
	new JButton("Tux"),
	new JButton("Ctr"),
	new JButton("Gato"),
	new JButton("Milu")};	
// fuente para botones y etiqueta
Font letra = new Font("Verdana", Font.BOLD, 12);
// etiqueta para mostrar las imagenes JPG
private JLabel imgLabel = new JLabel();
// etiqueta para mostrar la ruta a los archivos
private JLabel rutaLabel = new JLabel();
// botones de la parte inferior
private JButton Codigo = new JButton("Archivo fuente java");
private JButton Salir = new JButton("Salir del programa");
 // Cadena para usar en setLabelPicture(), coincide con el nombre de la imagen JPG y con el texto del boton
private String nombreFoto;

Métodos de entrada al programa y creación de la interfaz gráfica.

// METODO DE ENTRADA AL PROGRAMA
public static void main(String[] args) {
// instancia de la clase principal, hereda de JFrame
new Botones_fotos(); }

// METODO CONSTRUCTOR QUE CREA Y MUESTRA LA INTERFAZ
public Botones_fotos() {
// la variable especial this se usa en metodos de instancia para hacer referencia 
// al objeto que contiene al metodo, aqui equivale a JFrame 
// lo que pasa al cerrar la ventana: salir del programa
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}

Mostrar los botones, configurar la fuente y enlazarlos con addActionListener.

// mostrar los botones inferiores, configurar la fuente y enlazarlos con addActionListener
Codigo.setActionCommand ("Codigo");
Codigo.addActionListener(this);

Salir.setActionCommand ("Salir");
Salir.addActionListener(this);

// mostrar los botones superiores, configurar la fuente y enlazarlos con addActionListener
for(int i = 0; i < strBotones.length; i++) {
	pBotones.add(strBotones[i]);
	strBotones[i].setFont(letra);
	strBotones[i].addActionListener(this); }

El aspecto de las etiquetas también se puede configurar.

// configurar la etiqueta imgLabel
imgLabel.setHorizontalAlignment(JLabel.CENTER);
imgLabel.setOpaque(true);
imgLabel.setBackground(Color.gray);

Rellenar los paneles contenedores.

// colocar elementos en los paneles, panel1 es contentPane del JFrame
panel1.setOpaque(true);
this.setContentPane(panel1);

panel1.add(panelSup, BorderLayout.NORTH);
panelSup.add(pBotones);
panelSup.add(pLabel);

panel1.add(imgLabel, BorderLayout.CENTER);
panel1.add(pBotones2, BorderLayout.SOUTH);
pBotones2.add(Codigo);
pBotones2.add(Salir);
pLabel.add(rutaLabel);

// mostrar la ventana
this.setTitle("Botones y Fotos");
this.setSize(new Dimension(720,582));
// ajustar el marco a sus contenedores
//this.pack();
// centrar el formulario en la pantalla
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setVisible(true);

Método setLabelPicture. Carga la imagen cuyo nombre coincide con el texto del botón y muestra la ruta quitando los caracteres %20 que Java coloca en lugar de los espacios en blanco.

// MOSTRAR LA IMAGEN EN LA ETIQUETA
private void setLabelPicture() {
	imgLabel.setText("");
	// texto del boton con extension jpg = nombre del archivo JPG
	String nombreCompleto = "/img/" + nombreFoto + ".jpg";
	// buscar el archivo JPG dentro del archivo JAR,
	// para poder usar la clase URL hay que importar el paquete java.net.URL
	URL url = this.getClass().getResource( nombreCompleto );
	String urlS = url.toString();
	// Java coloca los caracteres %20 en lugar de los espacios en blanco de la ruta, se quitan para mejorar su aspecto
	urlS = urlS.replace("%20"," ");
	// informar de la ruta a la imagen seleccionada, para ver la presentacion de URL
	rutaLabel.setText("" + urlS);
	// informar tambien con cuadro de mensaje
	//JOptionPane.showMessageDialog(null, "Ruta a la imagen seleccionada: " + urlS, "URL de la imagen", JOptionPane.PLAIN_MESSAGE);
	// JLabel.setIcon(Icon) define el icono mostrado en la etiqueta, centrado en horizontal y en vertical
	imgLabel.setIcon(new ImageIcon(url));
}

Si se desea que el programa arranque con una de las imágenes visible, se llama al método durante la carga del programa, Si se prefiere que arranque en blanco, se comentan estas 2 líneas.

// llamar al metodo setLabelPicture() si se prefiere que el programa arranque ya con imagen cargada
// comentar las 2 lineas si se prefiere que arranque vacio sin imagen cargada
nombreFoto = "Milu"; 	//  imagen que aparece al arrancar el programa
setLabelPicture();

Al pulsar en el botón Codigo se muestra la segunda ventana en la que se ha añadido un objeto JEditorPane al que se le pasa el texto del archivo .html con el código Java de la ventana principal, con la sintaxis coloreada. Al pulsar el botón Salir se sale del programa. A l pulsar cualquier otro botón se desencadena el evento que lleva al método que muestra las fotos.

// LO QUE SUCEDE AL PULSAR UNO DE LOS BOTONES
public void actionPerformed(ActionEvent e) {
	// si se ha pulsado en el boton con el texto Archivo fuente Java
	// (si ActionCommand es Codigo) mostrar la ventana con codigo Java
	if ("Codigo".equals(e.getActionCommand())) {	
		// mostrar un objeto Botones_fotos_code, es el marco para la segunda ventana
		Botones_fotos_code codeForm = new Botones_fotos_code();
		//codeForm.show(); } --> obsoleto
		codeForm.setVisible(true); }
	// si se ha pulsado en el boton Salir (si ActionCommand es Salir)
	else if ("Salir".equals(e.getActionCommand())) {
		System.exit(0); }	
	// si se ha pulsado en cualquier otro boton
	else {
		// e.getActionCommand() equivale al texto del boton
		// para pasarle al metodo e.getActionCommand() el nombre de la imagen
		// que es el texto del boton on extension jpg 
		nombreFoto = e.getActionCommand();
		setLabelPicture(); }
}

Crear el archivo JAR

Es necesario incorporar al archivo todos los elementos: las clases como se hace habitualmente, las imágenes de la carpeta img y el archivo .html de la carpeta code.

Código fuente de ambas clases: java1 y java2.

Programa completo en zip.