Saltar al contenido principal

Layout managers

Los layout managers (gestores de disposición) controlan cómo se posicionan y dimensionan los componentes dentro de un contenedor. Usar layouts es la forma correcta de hacer interfaces responsivas que se adapten al redimensionado de la ventana.

FlowLayout

Coloca los componentes en fila, de izquierda a derecha, pasando a la siguiente línea cuando no caben.

// Alineación: LEFT, CENTER (defecto), RIGHT, LEADING, TRAILING
// Hgap: espacio horizontal entre componentes
// Vgap: espacio vertical entre filas
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));

panel.add(new JLabel("Nombre:"));
panel.add(new JTextField(15));
panel.add(new JButton("Buscar"));

Cuándo usarlo: Barras de botones simples, toolbars horizontales, grupos pequeños de componentes.

BorderLayout

Divide el contenedor en 5 zonas: NORTH, SOUTH, EAST, WEST y CENTER.

JPanel panel = new JPanel(new BorderLayout(5, 5)); // hgap, vgap

panel.add(new JLabel("Cabecera", JLabel.CENTER), BorderLayout.NORTH);
panel.add(new JScrollPane(new JTextArea()), BorderLayout.CENTER); // ocupa el espacio restante
panel.add(new JList<>(), BorderLayout.EAST);
panel.add(new JTextField("Buscar..."), BorderLayout.SOUTH);
// WEST no se usa en este ejemplo

Reglas:

  • Solo un componente por zona.
  • CENTER se expande para llenar todo el espacio disponible.
  • Las zonas no utilizadas no ocupan espacio.
  • JFrame usa BorderLayout por defecto.

Cuándo usarlo: Estructura clásica de aplicación (cabecera + contenido central + barra de estado).

GridLayout

Coloca los componentes en una cuadrícula de filas × columnas, todos del mismo tamaño.

// 3 filas, 2 columnas, 5px horizontal, 5px vertical entre celdas
JPanel panel = new JPanel(new GridLayout(3, 2, 5, 5));

panel.add(new JLabel("Nombre:"));
panel.add(new JTextField());
panel.add(new JLabel("Email:"));
panel.add(new JTextField());
panel.add(new JLabel("Teléfono:"));
panel.add(new JTextField());

Reglas:

  • Si pones 0 en filas: las filas crecen automáticamente.
  • Todos los componentes tienen exactamente el mismo tamaño.

Cuándo usarlo: Formularios simples, teclados numéricos, calculadoras, tableros de juego.

GridBagLayout

El layout más potente y flexible de Swing. Permite que cada componente ocupe diferentes números de celdas, con pesos de expansión independientes.

JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();

// Configuración base (se reutiliza modificando campos)
gbc.insets = new Insets(5, 5, 5, 5); // Margen exterior (top, left, bottom, right)
gbc.fill = GridBagConstraints.HORIZONTAL; // Cómo rellenar la celda

// Etiqueta Nombre (columna 0, fila 0)
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 0; // No se expande horizontalmente
panel.add(new JLabel("Nombre:"), gbc);

// Campo Nombre (columna 1, fila 0)
gbc.gridx = 1;
gbc.gridy = 0;
gbc.weightx = 1.0; // Se expande para llenar el espacio
panel.add(new JTextField(), gbc);

// Etiqueta Email (columna 0, fila 1)
gbc.gridx = 0;
gbc.gridy = 1;
gbc.weightx = 0;
panel.add(new JLabel("Email:"), gbc);

// Campo Email (columna 1, fila 1)
gbc.gridx = 1;
gbc.gridy = 1;
gbc.weightx = 1.0;
panel.add(new JTextField(), gbc);

// Botón que ocupa 2 columnas (columna 0-1, fila 2)
gbc.gridx = 0;
gbc.gridy = 2;
gbc.gridwidth = 2; // Ocupa 2 columnas
gbc.weightx = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor = GridBagConstraints.CENTER;
panel.add(new JButton("Enviar"), gbc);

Propiedades de GridBagConstraints

PropiedadDescripción
gridxColumna (empieza en 0). RELATIVE = siguiente columna automático
gridyFila (empieza en 0)
gridwidthNúmero de columnas que ocupa el componente
gridheightNúmero de filas que ocupa el componente
weightxPeso de expansión horizontal (0 = no crece, 1.0 = crece todo)
weightyPeso de expansión vertical
fillNONE, HORIZONTAL, VERTICAL, BOTH
anchorPosición si el componente no llena la celda: CENTER, NORTH...
insetsMargen exterior del componente
ipadx/ipadyMargen interior (padding) del componente

BoxLayout

Organiza los componentes en una fila o columna, respetando los tamaños preferidos de cada uno.

JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); // Columna vertical
// BoxLayout.X_AXIS → fila horizontal

panel.add(new JLabel("Título"));
panel.add(Box.createVerticalStrut(10)); // Espacio rígido de 10px
panel.add(new JTextField());
panel.add(Box.createRigidArea(new Dimension(0, 10))); // Equivalente
panel.add(Box.createVerticalGlue()); // Espacio flexible (empuja hacia arriba)
panel.add(new JButton("Aceptar"));
Buena práctica

Nunca uses coordenadas absolutas (setLayout(null) + setBounds()): la interfaz se rompe al cambiar el tamaño o la resolución. Solo tiene sentido en prototipados rápidos.

Espaciadores de Box

MétodoDescripción
Box.createHorizontalStrut(n)Espacio rígido horizontal de n píxeles
Box.createVerticalStrut(n)Espacio rígido vertical de n píxeles
Box.createRigidArea(Dimension)Espacio rígido con ancho y alto
Box.createHorizontalGlue()Espacio flexible horizontal (llena el hueco)
Box.createVerticalGlue()Espacio flexible vertical

Cuándo usarlo: Paneles laterales, diálogos con botones alineados, menús verticales.

CardLayout

Permite apilar paneles y mostrar solo uno a la vez. Ideal para asistentes (wizards) o paneles con pestañas personalizadas.

JPanel contenedor = new JPanel();
CardLayout card = new CardLayout();
contenedor.setLayout(card);

// Añadir "páginas" con nombre
contenedor.add(new JPanel() {{ add(new JLabel("Pantalla 1")); }}, "pagina1");
contenedor.add(new JPanel() {{ add(new JLabel("Pantalla 2")); }}, "pagina2");
contenedor.add(new JPanel() {{ add(new JLabel("Pantalla 3")); }}, "pagina3");

// Navegar entre páginas
card.show(contenedor, "pagina2"); // Mostrar página específica
card.next(contenedor); // Siguiente
card.previous(contenedor); // Anterior
card.first(contenedor); // Primera
card.last(contenedor); // Última

SpringLayout

Layout avanzado que define posiciones mediante restricciones de distancia entre los bordes de los componentes. Muy flexible pero verboso.

JPanel panel = new JPanel(new SpringLayout());
JLabel lbl = new JLabel("Nombre:");
JTextField txt = new JTextField(15);
panel.add(lbl);
panel.add(txt);

SpringLayout layout = (SpringLayout) panel.getLayout();

// El borde WEST de lbl está a 5px del borde WEST del panel
layout.putConstraint(SpringLayout.WEST, lbl, 5, SpringLayout.WEST, panel);
// El borde NORTH de lbl está a 5px del borde NORTH del panel
layout.putConstraint(SpringLayout.NORTH, lbl, 5, SpringLayout.NORTH, panel);
// El borde WEST de txt está a 10px del borde EAST de lbl
layout.putConstraint(SpringLayout.WEST, txt, 10, SpringLayout.EAST, lbl);
// Alinear verticalmente lbl y txt
layout.putConstraint(SpringLayout.NORTH, txt, 0, SpringLayout.NORTH, lbl);

Composición de layouts (el patrón real)

En aplicaciones reales se combinan layouts anidando paneles.

// Panel principal con BorderLayout
JPanel main = new JPanel(new BorderLayout(5, 5));

// Cabecera
JLabel header = new JLabel("Mi App", JLabel.CENTER);
header.setFont(new Font("Arial", Font.BOLD, 20));
main.add(header, BorderLayout.NORTH);

// Formulario central con GridBagLayout
JPanel form = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(4, 4, 4, 4);
c.fill = GridBagConstraints.HORIZONTAL;

c.gridx = 0; c.gridy = 0; c.weightx = 0;
form.add(new JLabel("Usuario:"), c);
c.gridx = 1; c.weightx = 1;
form.add(new JTextField(20), c);

c.gridx = 0; c.gridy = 1; c.weightx = 0;
form.add(new JLabel("Contraseña:"), c);
c.gridx = 1; c.weightx = 1;
form.add(new JPasswordField(20), c);

main.add(form, BorderLayout.CENTER);

// Barra de botones con FlowLayout alineado a la derecha
JPanel botones = new JPanel(new FlowLayout(FlowLayout.RIGHT));
botones.add(new JButton("Cancelar"));
botones.add(new JButton("Aceptar"));
main.add(botones, BorderLayout.SOUTH);

Bordes decorativos con BorderFactory

Los bordes no son layouts, pero complementan la organización visual:

JPanel panel = new JPanel();

// Tipos de borde
panel.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
panel.setBorder(BorderFactory.createEtchedBorder());
panel.setBorder(BorderFactory.createRaisedBevelBorder());
panel.setBorder(BorderFactory.createLoweredBevelBorder());
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); // Solo padding

// TitledBorder — borde con título (muy común en formularios)
panel.setBorder(BorderFactory.createTitledBorder("Datos personales"));

// Borde compuesto
panel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Opciones"),
BorderFactory.createEmptyBorder(5, 5, 5, 5)
));