Saltar al contenido principal

Introducción a Java Swing

Swing es la biblioteca estándar de Java para crear interfaces gráficas de usuario (GUI). Forma parte del paquete javax.swing y está construida sobre AWT (Abstract Window Toolkit), la biblioteca gráfica original de Java.

A diferencia de AWT, Swing es completamente independiente del sistema operativo: sus componentes están dibujados directamente por Java, no por el sistema nativo, lo que garantiza un comportamiento uniforme en todas las plataformas.

AWT vs Swing

CaracterísticaAWTSwing
Paquetejava.awtjavax.swing
ComponentesNativos del SODibujados por Java (ligeros)
PersonalizaciónLimitadaMuy alta
Portabilidad visualVaría por plataformaConsistente en todas las plataformas
RendimientoMás rápido (delegado al SO)Ligeramente más lento
Componentes doblesNoSí (por ejemplo, JTable, JTree)
Nota

En proyectos modernos, prioriza el uso de Swing (o JavaFX). AWT se conserva como base interna.

Arquitectura de Swing

Swing sigue el patrón MVC (Model-View-Controller):

  • Model: los datos del componente. Por ejemplo, DefaultTableModel para una tabla.
  • View: cómo se dibuja el componente en pantalla.
  • Controller: la lógica que reacciona a los eventos del usuario.

En Swing, la vista y el controlador suelen estar fusionados en el objeto del componente, mientras que el modelo es separable.

La jerarquía de clases principal

java.lang.Object
└── java.awt.Component
└── java.awt.Container
└── javax.swing.JComponent
├── JLabel
├── JButton
├── JTextField
├── JPanel
└── ... (todos los componentes J*)

Además, existen las ventanas de alto nivel (Top-Level Containers):

java.awt.Window
├── java.awt.Frame
│ └── javax.swing.JFrame ← ventana principal
└── java.awt.Dialog
└── javax.swing.JDialog ← ventana secundaria/modal

JFrame: la ventana principal

JFrame es la clase de Swing que representa la ventana principal de una aplicación de escritorio. Hereda de java.awt.Frame y añade soporte completo para los componentes Swing.

Una JFrame actúa como contenedor de alto nivel: no vive dentro de otro componente, sino que es la raíz del árbol de la interfaz gráfica. Internamente está formada por varias capas, pero la que nos interesa es el content pane, que es donde se añaden los componentes visibles (botones, etiquetas, paneles, etc.).

Sus responsabilidades principales son:

  • Dibujar el marco de la ventana (título, botones de minimizar/maximizar/cerrar).
  • Gestionar el ciclo de vida de la ventana (mostrar, ocultar, cerrar).
  • Contener y organizar los componentes de la interfaz a través de su content pane.
  • Despachar los eventos del sistema operativo al resto de componentes.

Para usar JFrame basta con:

  • Instanciarla new JFrame().
  • Configurar sus propiedades básicas (tamaño, comportamiento al cerrar, etc.).
  • Añadir los componentes necesarios.
  • Hacer la ventana visible con setVisible(true).

Tu primera ventana

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class HolaMundo {

public static void main(String[] args) {
// IMPORTANTE: crear la GUI en el Event Dispatch Thread (EDT)
SwingUtilities.invokeLater(() -> {
JFrame ventana = new JFrame("Mi primera ventana");

// Qué hacer al cerrar la ventana (EXIT_ON_CLOSE cierra la JVM)
ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

// Añadir un componente
ventana.add(new JLabel("¡Hola, Swing!", JLabel.CENTER));

// Tamaño de la ventana en píxeles
ventana.setSize(400, 200);

// Centrar en pantalla
ventana.setLocationRelativeTo(null);

// Mostrar la ventana
ventana.setVisible(true);
});
}
}
¿Por qué SwingUtilities.invokeLater?

Swing no es thread-safe (no está diseñado para ser usado desde múltiples hilos). Por lo tanto, toda creación y manipulación de componentes debe hacerse en el Event Dispatch Thread (EDT).

El método invokeLater encola la tarea en ese hilo. Si no lo haces, puedes sufrir condiciones de carrera y comportamientos impredecibles.

Estructura recomendada de una aplicación

En lugar de poner todo en main, lo habitual es crear una clase que extienda JFrame (o que lo contenga como campo):

import javax.swing.*;

public class MiVentana extends JFrame {

public MiVentana() {
super("Mi Aplicación");
inicializarUI();
}

private void inicializarUI() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(600, 400);
setLocationRelativeTo(null);

// Aquí se añaden los componentes...
JLabel etiqueta = new JLabel("Bienvenido", JLabel.CENTER);
add(etiqueta);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new MiVentana().setVisible(true);
});
}
}

Opciones de setDefaultCloseOperation

ConstanteComportamiento
DO_NOTHING_ON_CLOSENo hace nada (tú controlas el cierre manualmente)
HIDE_ON_CLOSEOculta la ventana pero no cierra la JVM
DISPOSE_ON_CLOSELibera los recursos de la ventana
EXIT_ON_CLOSECierra la JVM completamente

Importaciones más comunes

import javax.swing.*;          // Todos los componentes Swing (JFrame, JButton...)
import java.awt.*; // Layout managers, Color, Font, Graphics...
import java.awt.event.*; // Listeners de eventos (ActionListener, MouseListener...)