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 |
|---|---|
![]() | ![]() |
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:
| Tema | Línea | Aspecto |
|---|---|---|
| Claro | FlatLightLaf.setup(); | Fondo claro, como el de estos ejemplos |
| Oscuro | FlatDarkLaf.setup(); | Fondo oscuro |
| Claro, al estilo de IntelliJ | FlatIntelliJLaf.setup(); | Parecido al editor IntelliJ IDEA |
| Oscuro, al estilo de IntelliJ | FlatDarculaLaf.setup(); | Parecido a IntelliJ en modo oscuro |
| Al estilo de macOS | FlatMacLightLaf.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:
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.
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 claro | Tras pulsar «Modo 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ío | campo.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "tu@correo.es"); |
| Retocar el estilo de un componente | boton.putClientProperty(FlatClientProperties.STYLE, "arc: 999; background: #007AFB"); |
| Usar un estilo de texto ya preparado | titulo.putClientProperty(FlatClientProperties.STYLE_CLASS, "h2"); |
Lo que va en STYLE es parecido al CSS de una web: pares propiedad: valor separados por ;.
| Propiedad | Qué cambia | Ejemplo |
|---|---|---|
arc | Lo redondeadas que son las esquinas (999 = completamente redondo) | arc: 12 |
background | El color de fondo | background: #007AFB |
foreground | El color del texto | foreground: #FFFFFF |
font | La letra: bold, italic, o un tamaño relativo | font: bold +2 |
showRevealButton | En un JPasswordField, el ojo para ver la contraseña | showRevealButton: 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:
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);
});
}
}
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:
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íntoma | Qué pasa | Cómo se arregla |
|---|---|---|
| La ventana sale con el aspecto antiguo | setup() está después de crear la ventana, o no está | Ponlo como primera línea del main |
| Al cambiar de tema, solo cambia una parte | Falta repintar | Llama a FlatLaf.updateUI(); después del setup() |
| El color de acento no cambia | setGlobalExtraDefaults está después del setup() | Ponlo antes |
| Un estilo no se aplica | Una propiedad mal escrita dentro del texto de STYLE | Revisa el nombre y el ; entre propiedades |



