Codemaker Interfaces

Interfaces Tema 5

MigLayout

MigLayout es el layout que usaremos para todo, también en el proyecto final. No viene con Java (es una de las librerías de Preparar el ordenador), pero hace en un solo panel lo que con los layouts clásicos necesita varios anidados.

La idea: una rejilla#

MigLayout coloca los componentes en una rejilla de filas y columnas, como una tabla. Cada add(…) ocupa la celda siguiente, y tú decides cómo es cada columna:

MigLayout coloca los componentes en una rejilla de filas y columnas, con márgenes (insets) y huecos (gap)

Se configura con tres textos al crearlo:

Java
new MigLayout("wrap 2, insets 20", "[right][grow, fill]", "")
//             └ 1. el panel ┘     └ 2. las columnas ┘   └ 3. las filas
TextoQué diceEn el ejemplo
1. Del panelReglas generaleswrap 2: salta de fila cada 2 componentes; insets 20: 20 px de margen
2. De las columnasUna pareja de corchetes […] por columna, con sus reglas[right]: la primera alineada a la derecha; [grow, fill]: la segunda crece y estira lo que tiene
3. De las filasIgual, para las filas"": nada especial

Y cada componente puede llevar sus propias reglas, como segundo dato del add: panel.add(boton, "span 2").

Un formulario#

Java
import javax.swing.*;
import com.formdev.flatlaf.FlatLightLaf;
import net.miginfocom.swing.MigLayout;

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

            // 2 columnas: la primera alineada a la derecha, la segunda crece
            JPanel panel = new JPanel(new MigLayout("wrap 2, insets 20", "[right][grow, fill]"));

            panel.add(new JLabel("Nombre"));
            panel.add(new JTextField());
            panel.add(new JLabel("Edad"));
            panel.add(new JSpinner(new SpinnerNumberModel(16, 6, 99, 1)), "growx 0");
            panel.add(new JLabel("Nivel"));
            panel.add(new JComboBox<>(new String[] {"Junior", "Senior", "Master", "DEV"}));
            panel.add(new JLabel("Observaciones"), "top");
            panel.add(new JScrollPane(new JTextArea(4, 20)));

            panel.add(new JButton("Cancelar"), "span 2, split 2, align right");
            panel.add(new JButton("Guardar"));

            ventana.add(panel);
            ventana.setSize(460, 330);
            ventana.setLocationRelativeTo(null);
            ventana.setVisible(true);
        });
    }
}

El formulario «Nuevo alumno»: etiquetas a la izquierda alineadas a la derecha, campos a la derecha que ocupan todo el ancho, y los botones Cancelar y Guardar abajo a la derecha

Fíjate en tres detalles:

CódigoQué consigue
"growx 0" en el JSpinnerQue el número no se estire a todo el ancho, aunque la columna sea fill
"top" en «Observaciones»Que la etiqueta quede arriba, a la altura de la primera línea del texto, y no centrada
"span 2, split 2, align right" en CancelarQue la última fila ocupe las 2 columnas (span 2), que en esa celda quepan 2 botones (split 2) y que vayan a la derecha

Consejo

Si no entiendes por qué algo sale donde sale, añade debug a las reglas del panel: new MigLayout("wrap 2, insets 20, debug", …). MigLayout dibuja las celdas con líneas de colores:

El mismo formulario con debug: cada celda rodeada por una línea discontinua roja y cada componente por una verde

Un panel de tarjetas#

Con lo mismo se hacen las pantallas de un dashboard, como el del proyecto final: cuatro columnas iguales, y cada tarjeta dice cuántas ocupa.

Java
import java.awt.Color;
import javax.swing.*;
import com.formdev.flatlaf.FlatLightLaf;
import net.miginfocom.swing.MigLayout;

public class PanelMig {
    public static void main(String[] args) {
        FlatLightLaf.setup();
        SwingUtilities.invokeLater(() -> {
            JFrame ventana = new JFrame("Panel de la academia");
            ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            // 4 columnas iguales (sg = mismo tamaño) que crecen con la ventana
            JPanel panel = new JPanel(new MigLayout("insets 16, gap 12",
                    "[grow, fill, sg][grow, fill, sg][grow, fill, sg][grow, fill, sg]",
                    "[][grow, fill]"));

            panel.add(tarjeta("Alumnos", "128"));
            panel.add(tarjeta("Matrículas", "34"));
            panel.add(tarjeta("Cursos", "6"));
            panel.add(tarjeta("Media", "7,4"), "wrap");

            panel.add(tarjeta("Gráfica", "(ocupa 3 columnas)"), "span 3");
            panel.add(tarjeta("Avisos", "(1 columna)"));

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

    // Una "tarjeta": un panel con un título pequeño y un dato grande
    static JPanel tarjeta(String titulo, String dato) {
        JPanel t = new JPanel(new MigLayout("wrap, insets 14"));
        t.setBackground(Color.WHITE);
        t.setBorder(BorderFactory.createLineBorder(new Color(0xDCE4EE)));
        JLabel valor = new JLabel(dato);
        valor.setFont(valor.getFont().deriveFont(20f));
        t.add(new JLabel(titulo));
        t.add(valor);
        return t;
    }
}

Un panel con cuatro tarjetas pequeñas arriba (Alumnos, Matrículas, Cursos y Media) y debajo una tarjeta ancha de tres columnas y otra de una

Las tarjetas son a su vez JPanel con su propio MigLayout: un panel dentro de otro, pero ahora cada uno con muy poco código.

Consejo

Todas las reglas, ordenadas por lo que quieres conseguir y con un ejemplo de cada una, están en la hoja de consulta de MigLayout. Tenla abierta mientras programas.

Errores frecuentes#

Mensaje o síntomaQué significaCómo se arregla
cannot find symbol en MigLayoutFalta el import o la libreríaimport net.miginfocom.swing.MigLayout;, y los dos .jar en lib
IllegalArgumentException: Error parsing Constraint: 'grwox'Una regla mal escrita (aquí, grwox en vez de growx). Salta al ejecutar, no al compilarCorrige la palabra que dice el mensaje
Todo sale en una sola filaFalta wrap, en el panel (wrap 2) o en el último componente de cada filaAñade el wrap
Los campos no se estiran al agrandar la ventanaLa columna no tiene grow y fill"[right][grow, fill]"
No entiendes por qué algo sale donde sale—Añade debug al panel y mira las celdas