Manejo de Eventos en Java Swing

Introducción

Hasta ahora hemos aprendido a crear interfaces gráficas en Java con Swing, organizando los componentes con distintos Layouts. Sin embargo, nuestras aplicaciones aún no hacen nada cuando el usuario interactúa con ellas. En esta sesión aprenderemos sobre el manejo de eventos en Swing, que nos permitirá programar respuestas a acciones como clics en botones, movimientos del mouse o pulsaciones de teclas.

¿Qué es un evento en Java Swing?

Un evento es cualquier acción realizada por el usuario que genera una señal en la interfaz gráfica. Algunos ejemplos comunes son:

  • Hacer clic en un botón.
  • Escribir en un cuadro de texto.
  • Mover el ratón sobre un componente.
  • Cerrar una ventana.

Para que nuestra aplicación responda a estos eventos, debemos registrar y manejar eventos mediante Listeners (escuchadores de eventos).


Manejo de eventos con ActionListener

Uno de los eventos más comunes es hacer clic en un botón. Para capturar este evento en Swing, utilizamos la interfaz ActionListener, que se encuentra en el paquete java.awt.event.

Pasos para manejar eventos en un botón

  1. Crear el componente objetivo del evento en la interfaz.
  2. Registrar un escuchador de eventos (ActionListener).
  3. Implementar el método actionPerformed() para definir la acción a ejecutar cuando se lance el evento.

Ejemplo básico: Capturar clic en un botón

Supongamos que tenemos una interfaz con un botón llamado btnSaludar. Queremos que, al hacer clic en él, aparezca un mensaje en la consola.

import javax.swing.*;
import java.awt.event.*; // Importamos los eventos

public class EventoBoton {
    public static void main(String[] args) {
        JFrame ventana = new JFrame("Ejemplo de Evento");
        ventana.setSize(300, 200);
        ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        JButton btnSaludar = new JButton("Haz clic");
        ventana.add(btnSaludar);
        
        // Agregar el ActionListener al botón
        btnSaludar.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("¡Hola! Has hecho clic en el botón.");
            }
        });
        
        ventana.setVisible(true);
    }
}

Explicación del código

  • addActionListener(): Asigna un escuchador de eventos al botón.
  • Clase anónima ActionListener: Implementa el método actionPerformed(), que ejecuta el código cuando se hace clic en el botón.
  • System.out.println(): Muestra un mensaje en la consola.

Manejo de eventos con clases internas

En el ejemplo anterior usamos una clase anónima, pero también podemos manejar eventos con clases internas para hacer el código más organizado y reutilizable.

import javax.swing.*;
import java.awt.event.*;

public class EventoConClaseInterna {
    public static void main(String[] args) {
        new MiVentana();
    }
}

class MiVentana extends JFrame {
    JButton btnSaludar;

    public MiVentana() {
        setTitle("Ejemplo de Evento con Clase Interna");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        btnSaludar = new JButton("Saludar");
        add(btnSaludar);
        
        // Agregamos un manejador de eventos de clase interna
        btnSaludar.addActionListener(new ManejadorEventos());
        
        setVisible(true);
    }
    
    static class ManejadorEventos implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("¡Has hecho clic en el botón!");
        }
    }
}

Ventajas del uso de clases internas

  • ✅ Código más limpio y estructurado.
  • ✅ Permite reutilizar la lógica de manejo de eventos.
  • ✅ Mantiene la organización de la clase principal.

Manejo de eventos con expresiones lambda (Java 8+)

Si usamos Java 8 o superior, podemos simplificar el código con expresiones lambda, eliminando la necesidad de clases anónimas.

btnSaludar.addActionListener(e -> System.out.println("¡Has hecho clic!"));

Ventajas de las lambdas

  • ✅ Código más compacto.
  • ✅ Más legible y fácil de entender.
  • ✅ Reduce la cantidad de líneas innecesarias.

Implementar ActionListener en el propio Formulario

Una forma de manejar eventos en Swing es hacer que el formulario (JFrame) implemente directamente la interfaz ActionListener (también podría hacerse en un JPanel de forma similar). Esto significa que la propia ventana actuará como su propio manejador de eventos.

🔹 Ejemplo: Implementación en el Formulario

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class VentanaFormulario extends JFrame implements ActionListener {
    private JButton boton1;
    private JButton boton2;

    public VentanaFormulario() {
        setTitle("Manejo de eventos");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new java.awt.FlowLayout());

        boton1 = new JButton("Botón 1");
        boton2 = new JButton("Botón 2");

        boton1.addActionListener(this);
        boton2.addActionListener(this);

        add(boton1);
        add(boton2);
        setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == boton1) {
            System.out.println("Se presionó el Botón 1");
        } else if (e.getSource() == boton2) {
            System.out.println("Se presionó el Botón 2");
        }
    }

    public static void main(String[] args) {
        new VentanaFormulario();
    }
}

🔹 Explicación

  • La clase VentanaFormulario extiende JFrame e implementa ActionListener.
  • Ambos botones (boton1 y boton2) registran la propia instancia de la ventana (this) como su ActionListener.
  • El método actionPerformed usa e.getSource() para determinar qué botón fue presionado.

Manejo de Eventos con una Clase Externa

En esta técnica, creamos una clase separada que implemente ActionListener y la usamos en la ventana principal. Esto mejora la separación entre la interfaz y la lógica de los eventos.

🔹 Ejemplo: Implementación con Clase Externa

Clase manejadora de eventos

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ManejadorBotones implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Se presionó: " + ((javax.swing.JButton) e.getSource()).getText());
    }
}

Clase del formulario

import javax.swing.*;

public class VentanaClaseExterna extends JFrame {
    private JButton boton1;
    private JButton boton2;

    public VentanaClaseExterna() {
        setTitle("Manejo de eventos con clase externa");
        setSize(300, 200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new java.awt.FlowLayout());

        boton1 = new JButton("Botón 1");
        boton2 = new JButton("Botón 2");

        ManejadorBotones manejador = new ManejadorBotones();
        boton1.addActionListener(manejador);
        boton2.addActionListener(manejador);

        add(boton1);
        add(boton2);
        setVisible(true);
    }

    public static void main(String[] args) {
        new VentanaClaseExterna();
    }
}

🔹 Explicación

  • Se crea una clase ManejadorBotones que implementa ActionListener y define la acción cuando se presiona un botón.
  • La clase VentanaClaseExterna crea una instancia del ManejadorBotones y la asocia a los botones.
  • Cuando se presiona un botón, el evento es manejado por ManejadorBotones, lo que mantiene limpio el código de la ventana.

Eventos en otros componentes de Swing

Además de los botones, podemos manejar eventos en otros componentes:

JTextField (eventos cuando el usuario presiona Enter)

JTextField campoTexto = new JTextField(20);
campoTexto.addActionListener(e -> System.out.println("Texto ingresado: " + campoTexto.getText()));

JCheckBox (eventos cuando el usuario marca/desmarca una casilla)

JCheckBox checkBox = new JCheckBox("Acepto los términos");
checkBox.addItemListener(e -> {
    if (checkBox.isSelected()) {
        System.out.println("Casilla marcada");
    } else {
        System.out.println("Casilla desmarcada");
    }
});

JComboBox (eventos cuando el usuario selecciona un elemento de la lista)

JComboBox<String> combo = new JComboBox<>(new String[]{"Opción 1", "Opción 2", "Opción 3"});
combo.addActionListener(e -> System.out.println("Seleccionaste: " + combo.getSelectedItem()));


Buenas prácticas en el manejo de eventos en Swing

  • Usar clases internas o lambdas para organizar mejor el código.
  • Evitar escribir lógica compleja dentro del actionPerformed(). En su lugar, llamar a métodos auxiliares.
  • Cerrar correctamente los recursos usados en los eventos, si se usan archivos o conexiones a bases de datos.
  • No bloquear el hilo principal de la interfaz (Event Dispatch Thread) con operaciones pesadas. Usar SwingWorker en estos casos.

📊 Tabla Comparativa de las Técnicas de Manejo de Eventos

MétodoVentajasInconvenientes
Clases anónimasCódigo compacto, fácil para eventos simples.Se vuelve confuso si hay muchos eventos.
Expresiones LambdaCódigo más limpio (a partir de Java 8).Solo sirve para interfaces funcionales.
Implementar ActionListener en el formularioCódigo más directo, sin clases adicionales.Difícil de mantener si hay muchos botones.
Clase internaSepara mejor la lógica del evento.Sigue estando dentro de la misma clase.
Clase externaMáxima separación entre lógica e interfaz, reutilizable.Puede ser innecesario para eventos pequeños.

🔥 ¿Cuándo Usar Cada Método?

  • Usar clases anónimas cuando el evento es simple y no afecta la legibilidad.
  • Usar lambdas si solo necesitas una acción rápida y el código debe ser corto y claro.
  • Implementar ActionListener en el formulario si hay pocos eventos y el código sigue siendo legible.
  • Usar una clase interna cuando hay múltiples eventos pero están relacionados con el mismo formulario.
  • Usar una clase externa cuando se necesita reutilizar el manejador de eventos o separar completamente la lógica de la interfaz.

Cada método tiene su uso ideal dependiendo de la cantidad de eventos, la reutilización del código y la claridad que se quiera mantener en la aplicación.

Ejercicios propuestos

Ejercicio 1: Botón que cambia de color

Crea una ventana con un JButton. Cada vez que el usuario haga clic en el botón, su color de fondo debe cambiar de forma aleatoria.

Pistas:

  • Usa Math.random() para generar colores aleatorios.
  • Implementa el evento utilizando un ActionListener.

Ejercicio 2: Contador de clics

Crea una interfaz con un JButton y un JLabel. Cada vez que el usuario haga clic en el botón, el JLabel debe actualizarse para mostrar el número total de clics realizados.

Pistas:

  • Usa una variable de instancia para contar los clics.
  • Implementa el ActionListener en una clase anónima o interna.

Ejercicio 3: Simulador de formulario

Diseña un formulario con un JTextField y un JButton. Cuando el usuario escriba su nombre en el campo de texto y pulse el botón, debe aparecer un mensaje de bienvenida en un JLabel.

Pistas:

  • Usa el método getText() del JTextField.
  • Usa JOptionPane.showMessageDialog() para mostrar mensajes emergentes.

Ejercicio 4: Gestión de teclado

Crea una interfaz con un JTextField y un JLabel. Cada vez que el usuario escriba una letra en el campo de texto, el JLabel debe actualizarse con el último carácter ingresado.

Pistas:

  • Usa un KeyListener.
  • Implementa el evento de keyTyped().

Ejercicio 5: Cambio de disposición con eventos

Crea una ventana con dos botones:

  • Uno debe cambiar el Layout de la ventana a FlowLayout.
  • El otro debe cambiarlo a GridLayout con 2 filas y 2 columnas.

Pistas:

  • Usa setLayout(new FlowLayout()) y setLayout(new GridLayout(2,2)).
  • Implementa los ActionListener en clases separadas.

Conclusión

El manejo de eventos es esencial para desarrollar aplicaciones interactivas en Java Swing. En esta sesión aprendimos:

  • ✅ Qué es un evento y cómo funciona.
  • ✅ Cómo manejar eventos con ActionListener.
  • ✅ Diferentes formas de manejar eventos: clases anónimas, internas y lambdas.
  • ✅ Eventos en distintos componentes.

En la siguiente sesión aprenderemos sobre validación de datos en formularios y control de eventos avanzados. 🚀


Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.