Codemaker Interfaces

Interfaces Tema 4

Layouts

Un layout decide dónde va cada componente dentro de un panel, y cómo se recolocan cuando la ventana cambia de tamaño. Se podría colocar todo a mano, diciendo la posición exacta de cada cosa en píxeles, pero entonces la ventana no se adapta:

Con posiciones fijas los componentes no se adaptan al tamaño de la ventana; con un layout sí

Por eso en Swing cada panel tiene su layout. Swing trae varios; estos son los clásicos:

LayoutCómo colocaPara qué se usa
FlowLayoutEn fila, y salta de línea cuando no cabeUna fila de botones
BorderLayoutEn cinco zonas: arriba, abajo, izquierda, derecha y centroEl esqueleto de una ventana
GridLayoutEn una cuadrícula de celdas igualesTeclados, tableros
CardLayoutUno encima de otro, y solo se ve unoCambiar de pantalla (en el último tema)

El layout se elige al crear el panel: new JPanel(new FlowLayout()).

FlowLayout: en fila#

FlowLayout: los componentes se colocan en fila de izquierda a derecha y saltan de línea cuando no caben

Java
import java.awt.FlowLayout;
import javax.swing.*;
import com.formdev.flatlaf.FlatLightLaf;

public class EjemploFlow {
    public static void main(String[] args) {
        FlatLightLaf.setup();
        SwingUtilities.invokeLater(() -> {
            JFrame ventana = new JFrame("FlowLayout");
            ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            JPanel panel = new JPanel(new FlowLayout());
            for (int i = 1; i <= 6; i++) {
                panel.add(new JButton("Botón " + i));
            }

            ventana.add(panel);
            ventana.setSize(420, 140);
            ventana.setLocationRelativeTo(null);
            ventana.setVisible(true);
        });
    }
}

Seis botones con FlowLayout: cuatro en la primera fila y dos en la segunda

Es el layout que tiene un JPanel si no le pones ninguno. Para alinear a la izquierda o a la derecha: new FlowLayout(FlowLayout.LEFT) o FlowLayout.RIGHT.

BorderLayout: cinco zonas#

BorderLayout: cinco zonas, NORTH, SOUTH, WEST, EAST y CENTER, que se queda con el espacio que sobra

Java
import java.awt.BorderLayout;
import javax.swing.*;
import com.formdev.flatlaf.FlatLightLaf;

public class EjemploBorder {
    public static void main(String[] args) {
        FlatLightLaf.setup();
        SwingUtilities.invokeLater(() -> {
            JFrame ventana = new JFrame("BorderLayout");
            ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            JPanel panel = new JPanel(new BorderLayout());
            panel.add(new JButton("NORTH"), BorderLayout.NORTH);
            panel.add(new JButton("SOUTH"), BorderLayout.SOUTH);
            panel.add(new JButton("WEST"), BorderLayout.WEST);
            panel.add(new JButton("EAST"), BorderLayout.EAST);
            panel.add(new JButton("CENTER"), BorderLayout.CENTER);

            ventana.add(panel);
            ventana.setSize(420, 260);
            ventana.setLocationRelativeTo(null);
            ventana.setVisible(true);
        });
    }
}

Cinco botones con BorderLayout, uno en cada zona

Consejo

Es el layout que tiene un JFrame: por eso, en la primera ventana, ventana.add(saludo) ponía el texto en el centro y ocupando todo. Si no dices zona, va a CENTER.

GridLayout: una cuadrícula#

GridLayout: una cuadrícula de celdas iguales que se rellenan en orden

Java
import java.awt.GridLayout;
import javax.swing.*;
import com.formdev.flatlaf.FlatLightLaf;

public class EjemploGrid {
    public static void main(String[] args) {
        FlatLightLaf.setup();
        SwingUtilities.invokeLater(() -> {
            JFrame ventana = new JFrame("GridLayout: calculadora");
            ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            JPanel panel = new JPanel(new GridLayout(4, 3, 6, 6));   // 4 filas, 3 columnas, 6 px de hueco
            String[] teclas = {"7", "8", "9", "4", "5", "6", "1", "2", "3", "0", ".", "="};
            for (String t : teclas) {
                panel.add(new JButton(t));
            }

            ventana.add(panel);
            ventana.setSize(260, 280);
            ventana.setLocationRelativeTo(null);
            ventana.setVisible(true);
        });
    }
}

Un teclado de calculadora hecho con GridLayout de 4 filas y 3 columnas

Paneles dentro de paneles#

Una ventana de verdad casi nunca se hace con un solo layout: se meten paneles dentro de otros, y cada uno usa el que mejor le va.

Paneles anidados: un BorderLayout con el título arriba, la lista en el centro y abajo un panel con FlowLayout para los botones

Java
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import javax.swing.*;
import com.formdev.flatlaf.FlatLightLaf;

public class EjemploAnidado {
    public static void main(String[] args) {
        FlatLightLaf.setup();
        SwingUtilities.invokeLater(() -> {
            JFrame ventana = new JFrame("Paneles dentro de paneles");
            ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            // Arriba: un título
            JLabel titulo = new JLabel("Notas de la clase");
            titulo.setFont(titulo.getFont().deriveFont(Font.BOLD, 18f));

            // En el centro: una lista
            JList<String> lista = new JList<>(new String[] {"Antonio: 7", "María: 9", "Juan: 6", "Elena: 8"});

            // Abajo: una fila de botones, alineados a la derecha
            JPanel botones = new JPanel(new FlowLayout(FlowLayout.RIGHT));
            botones.add(new JButton("Borrar"));
            botones.add(new JButton("Añadir"));

            JPanel panel = new JPanel(new BorderLayout(0, 10));
            panel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
            panel.add(titulo, BorderLayout.NORTH);
            panel.add(new JScrollPane(lista), BorderLayout.CENTER);
            panel.add(botones, BorderLayout.SOUTH);

            ventana.add(panel);
            ventana.setSize(360, 300);
            ventana.setLocationRelativeTo(null);
            ventana.setVisible(true);
        });
    }
}

La ventana resultante: el título arriba, la lista de notas en el centro y los botones Borrar y Añadir abajo a la derecha

Funciona, pero en cuanto la ventana tiene un formulario con varias filas, hacen falta muchos paneles anidados. Para eso usaremos MigLayout, en el tema siguiente: un solo layout que hace todo esto y más.

Errores frecuentes#

SíntomaQué pasaCómo se arregla
Solo se ve el último componente que has añadido a la ventanaEn un BorderLayout, todo lo que añades sin zona va a CENTER, y cada uno tapa al anteriorMete los componentes en un JPanel y añade el panel a la ventana
En GridLayout, los botones salen enormesGridLayout estira cada componente hasta llenar su celdaMete el GridLayout en una zona que no crezca, o usa MigLayout
setBounds o setLocation no hacen nadaEl layout del panel decide las posiciones y pisa las tuyasNo coloques a mano: elige el layout adecuado
Has añadido algo con la ventana ya visible y no apareceLa ventana no se ha recolocadoAñade todo antes de setVisible(true), o llama a panel.revalidate() después