Codemaker Interfaces

Interfaces Tema 7

FlatLaf: el aspecto

Swing decide cómo se dibuja cada componente con un Look and Feel (literalmente, «aspecto y tacto»). El que trae de serie se llama Metal y tiene más de veinte años. FlatLaf es otro, moderno, plano, con tema claro y oscuro: el mismo código, con otro aspecto.

Sin FlatLaf (Metal)Con FlatLaf
El catálogo de componentes con el aspecto Metal, antiguo, con degradados y bordes gruesosEl mismo catálogo con FlatLaf: plano, con bordes finos y colores suaves

La única diferencia entre las dos ventanas es la línea FlatLightLaf.setup();.

Los temas#

Se instala con una línea, al principio del main y antes de crear ninguna ventana:

TemaLíneaAspecto
ClaroFlatLightLaf.setup();Fondo claro, como el de estos ejemplos
OscuroFlatDarkLaf.setup();Fondo oscuro
Claro, al estilo de IntelliJFlatIntelliJLaf.setup();Parecido al editor IntelliJ IDEA
Oscuro, al estilo de IntelliJFlatDarculaLaf.setup();Parecido a IntelliJ en modo oscuro
Al estilo de macOSFlatMacLightLaf.setup(); y FlatMacDarkLaf.setup();Botones y colores de Mac

Cada uno se importa de com.formdev.flatlaf (los de macOS, de com.formdev.flatlaf.themes).

Cambiar de tema con la ventana abierta#

Basta con instalar el otro tema y avisar a FlatLaf para que repinte:

Java
FlatDarkLaf.setup();
FlatLaf.updateUI();

Este ejemplo tiene un botón de modo oscuro, y además usa tres detalles de FlatLaf que se ven en las capturas: un texto de ayuda dentro del campo de correo, el ojo para ver la contraseña y un botón redondo de color.

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

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

            JPanel panel = new JPanel(new MigLayout("wrap 2, insets 20, gap 12", "[right][grow, fill]"));

            JTextField correo = new JTextField();
            correo.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "tu@correo.es");
            JPasswordField clave = new JPasswordField();
            clave.putClientProperty(FlatClientProperties.STYLE, "showRevealButton: true");

            JToggleButton oscuro = new JToggleButton("Modo oscuro");
            oscuro.addActionListener(e -> {
                if (oscuro.isSelected()) {
                    FlatDarkLaf.setup();
                } else {
                    FlatLightLaf.setup();
                }
                FlatLaf.updateUI();       // repinta todas las ventanas con el tema nuevo
            });

            JButton entrar = new JButton("Entrar");
            entrar.putClientProperty(FlatClientProperties.STYLE,
                    "arc: 999; background: #007AFB; foreground: #FFFFFF; font: bold");

            panel.add(new JLabel("Correo"));
            panel.add(correo);
            panel.add(new JLabel("Contraseña"));
            panel.add(clave);
            panel.add(new JCheckBox("Recordarme"), "skip");
            panel.add(oscuro, "skip, split 2, growx 0");
            panel.add(entrar, "growx 0, gapleft push");

            ventana.add(panel);
            ventana.setSize(440, 260);
            ventana.setLocationRelativeTo(null);
            ventana.setVisible(true);
        });
    }
}
Tema claroTras pulsar «Modo oscuro»
El formulario con el tema claroEl mismo formulario con el tema oscuro

Retocar un componente: putClientProperty#

FlatLaf añade a los componentes opciones que Swing no tiene. Se ponen con putClientProperty, usando los nombres de FlatClientProperties:

Para…Código
Un texto de ayuda dentro de un campo vacíocampo.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "tu@correo.es");
Retocar el estilo de un componenteboton.putClientProperty(FlatClientProperties.STYLE, "arc: 999; background: #007AFB");
Usar un estilo de texto ya preparadotitulo.putClientProperty(FlatClientProperties.STYLE_CLASS, "h2");

Lo que va en STYLE es parecido al CSS de una web: pares propiedad: valor separados por ;.

PropiedadQué cambiaEjemplo
arcLo redondeadas que son las esquinas (999 = completamente redondo)arc: 12
backgroundEl color de fondobackground: #007AFB
foregroundEl color del textoforeground: #FFFFFF
fontLa letra: bold, italic, o un tamaño relativofont: bold +2
showRevealButtonEn un JPasswordField, el ojo para ver la contraseñashowRevealButton: true

Los estilos de texto ya preparados (STYLE_CLASS) son h00, h0, h1, h2, h3 y h4 para títulos, de más grande a más pequeño, y large, medium, small y mini para el texto normal.

El color de acento#

El acento es el color de lo que está marcado o activo: casillas, barras, el borde del campo en el que se escribe. Se cambia antes de instalar el tema:

Java
import java.util.Map;
import javax.swing.*;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.FlatLightLaf;
import net.miginfocom.swing.MigLayout;

public class Acento {
    public static void main(String[] args) {
        // El color de acento se elige ANTES de instalar el tema
        FlatLaf.setGlobalExtraDefaults(Map.of("@accentColor", "#F5A524"));
        FlatLightLaf.setup();

        SwingUtilities.invokeLater(() -> {
            JFrame ventana = new JFrame("Color de acento");
            ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JPanel panel = new JPanel(new MigLayout("wrap, insets 20, gap 12"));
            JCheckBox ch = new JCheckBox("Casilla marcada");
            ch.setSelected(true);
            JProgressBar barra = new JProgressBar(0, 100);
            barra.setValue(60);
            JSlider deslizador = new JSlider(0, 10, 4);
            panel.add(ch);
            panel.add(barra, "w 260!");
            panel.add(deslizador, "w 260!");
            panel.add(new JTextField("Escribe aquí"), "w 260!");
            ventana.add(panel);
            ventana.pack();
            ventana.setLocationRelativeTo(null);
            ventana.setVisible(true);
        });
    }
}

Componentes con el acento en ámbar: la casilla, la barra de progreso y el deslizador

Cambiar todos los componentes a la vez#

Para que todos los botones de la aplicación tengan las esquinas redondas, en vez de retocarlos uno a uno, se cambia la opción general después de instalar el tema:

Java
FlatLightLaf.setup();
UIManager.put("Button.arc", 999);
UIManager.put("Component.arc", 12);   // campos de texto, listas desplegables...

Nota

Cuando hay muchas opciones, se guardan en un fichero aparte, FlatLaf.properties, que hace de hoja de estilos de toda la aplicación, igual que un CSS. Así está hecha la maqueta del proyecto final.

Errores frecuentes#

SíntomaQué pasaCómo se arregla
La ventana sale con el aspecto antiguosetup() está después de crear la ventana, o no estáPonlo como primera línea del main
Al cambiar de tema, solo cambia una parteFalta repintarLlama a FlatLaf.updateUI(); después del setup()
El color de acento no cambiasetGlobalExtraDefaults está después del setup()Ponlo antes
Un estilo no se aplicaUna propiedad mal escrita dentro del texto de STYLERevisa el nombre y el ; entre propiedades