Swing y JFC: guía completa para interfaces gráficas en Java 21

Swing usa el modelo de delegación de eventos: un componente (fuente) genera un evento, y uno o más objetos (listeners) lo reciben y procesan.

El flujo es: componente genera evento → Event Dispatch Thread (EDT) lo encola → Swing llama al método del listener correspondiente.

ActionListener: el evento más común

JButton boton = new JButton("Guardar");

// Lambda (Java 8+, recomendado)
boton.addActionListener(e -> {
    System.out.println("Botón pulsado: " + e.getActionCommand());
    guardarDatos();
});

// Clase anónima (estilo clásico)
boton.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        guardarDatos();
    }
});

MouseListener y MouseMotionListener

panel.addMouseListener(new MouseAdapter() { // MouseAdapter implementa todos los métodos vacíos
    @Override
    public void mouseClicked(MouseEvent e) {
        System.out.println("Clic en: " + e.getX() + ", " + e.getY());
        if (e.getClickCount() == 2) System.out.println("Doble clic");
        if (SwingUtilities.isRightMouseButton(e)) mostrarMenuContextual(e);
    }
    @Override
    public void mouseEntered(MouseEvent e) { panel.setBackground(Color.LIGHT_GRAY); }
    @Override
    public void mouseExited(MouseEvent e)  { panel.setBackground(Color.WHITE); }
});

KeyListener y KeyBinding

Para atajos de teclado, prefiere KeyBindings sobre KeyListener: funcionan aunque el componente no tenga el foco:

// KeyBinding (recomendado)
InputMap im = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap am = panel.getActionMap();

im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK), "guardar");
am.put("guardar", new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) { guardarDatos(); }
});

Cambios en campos de texto

JTextField campo = new JTextField();

// DocumentListener: reacciona a cualquier cambio de texto
campo.getDocument().addDocumentListener(new DocumentListener() {
    @Override public void insertUpdate(DocumentEvent e)  { validar(); }
    @Override public void removeUpdate(DocumentEvent e)  { validar(); }
    @Override public void changedUpdate(DocumentEvent e) { validar(); }
});

// FocusListener: detecta cuando el campo gana/pierde el foco
campo.addFocusListener(new FocusAdapter() {
    @Override
    public void focusLost(FocusEvent e) {
        if (campo.getText().isBlank()) campo.setBorder(BorderFactory.createLineBorder(Color.RED));
    }
});

Regla fundamental: no bloquees el EDT

Las operaciones lentas (red, disco, BD) nunca deben ejecutarse directamente en los listeners, porque bloquean el EDT y la UI se congela. Usa SwingWorker para trabajo en segundo plano (se explica en el capítulo siguiente).

// MAL: bloquea la UI durante 5 segundos
boton.addActionListener(e -> {
    Thread.sleep(5000); // esto bloquea el EDT
    actualizar();
});

// BIEN: delegar a un hilo de fondo
boton.addActionListener(e -> {
    new MiWorker().execute(); // SwingWorker
});

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP