How to Use Java Look And Feel Selector to Change Your App’s ThemeJava’s Look and Feel (L&F) system lets you control the appearance and basic behavior of Swing applications. A Look and Feel Selector makes it easy for users or developers to switch themes at runtime — changing colors, component styles, and sometimes even layout nuances without restarting the application. This article explains the L&F architecture, how to build and integrate a selector, practical examples, and tips for compatibility and customization.
What is Look and Feel (L&F)?
Look and Feel is a pluggable architecture in Java Swing that defines how GUI components are drawn and how they behave. The L&F determines:
- Component visuals: buttons, menus, dialogs, tables.
- Default fonts, colors, and borders.
- Platform-specific behaviors (e.g., how menus behave on different OSes).
Swing provides several built-in Look and Feels:
- Metal (default cross-platform L&F)
- Nimbus (modern cross-platform L&F)
- Windows (on Windows platforms)
- GTK+ (on many Linux desktops)
- Motif (older Unix L&F)
Third-party L&Fs (e.g., FlatLaf, Darcula, Substance) offer modern or themed alternatives.
How Look and Feel Works Internally
Swing uses the UIManager class to manage L&F. Key points:
- UIManager stores UI defaults (colors, fonts, borders) in a UIDefaults table.
- Each installed L&F provides a set of defaults and component UI implementations.
- To change L&F you call UIManager.setLookAndFeel(…) and then update existing components (usually via SwingUtilities.updateComponentTreeUI(frame)).
Changing L&F at runtime requires revalidating and repainting components so they pick up new UI defaults.
Basic Selector: Changing L&F Programmatically
Below is a minimal example of switching Look and Feel at runtime using a JComboBox as the selector.
import javax.swing.*; import java.awt.*; import java.awt.event.*; public class LAFSelectorDemo { public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("L&F Selector Demo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); String[] lafNames = { "Metal", "Nimbus", "Windows", "GTK", "System" }; JComboBox<String> combo = new JComboBox<>(lafNames); combo.addActionListener(e -> { String selection = (String) combo.getSelectedItem(); try { switch (selection) { case "Nimbus": UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); break; case "Windows": UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); break; case "GTK": UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); break; case "System": UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); break; default: UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } SwingUtilities.updateComponentTreeUI(frame); frame.pack(); } catch (Exception ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(frame, "Failed to apply Look and Feel: " + ex.getMessage()); } }); JPanel panel = new JPanel(); panel.add(new JLabel("Choose Look & Feel:")); panel.add(combo); panel.add(new JButton("Sample Button")); panel.add(new JCheckBox("Sample Check")); frame.add(panel, BorderLayout.CENTER); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); }); } }
Notes:
- Use UIManager.getSystemLookAndFeelClassName() for the platform default.
- Some L&Fs are platform-specific and may not be available everywhere; catch exceptions.
Populating the Selector Dynamically
Rather than hardcoding names, list installed L&Fs:
UIManager.LookAndFeelInfo[] infos = UIManager.getInstalledLookAndFeels(); for (UIManager.LookAndFeelInfo info : infos) { System.out.println(info.getName() + " -> " + info.getClassName()); }
Use this array to fill your JComboBox with both display names and class names behind the scenes. This avoids referencing L&Fs that aren’t available on the running JVM.
Integrating Third-Party Look and Feels
Popular third-party options:
- FlatLaf (modern, flat design): add dependency and set “com.formdev.flatlaf.FlatLightLaf” or “FlatDarkLaf”.
- Darcula, Substance, JGoodies, Synthetica, etc.
Steps:
- Add the library jar to classpath (Maven/Gradle is preferred).
- Include the L&F class name in your selector options.
- Call UIManager.setLookAndFeel with that class name and update the UI.
Example for FlatLaf (Maven):
- Maven dependency:
- groupId: com.formdev
- artifactId: flatlaf
- version: latest (check current)
- Apply:
UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
Preserving State and Preferences
Common UX enhancements:
- Persist the selected L&F in a properties file or Preferences API so the app restores it on startup.
- Apply the saved L&F before creating components to avoid flicker or initial default L&F rendering.
Example using Preferences:
Preferences prefs = Preferences.userRoot().node("com.example.myapp"); String laf = prefs.get("lookAndFeel", UIManager.getSystemLookAndFeelClassName()); UIManager.setLookAndFeel(laf); // later when user changes: prefs.put("lookAndFeel", selectedClassName);
Theme Customization Beyond L&F
- UIDefaults: Modify individual entries (colors, fonts, borders) via UIManager.put(…) before creating components.
- UI delegates: For advanced customization, extend or replace specific ComponentUI classes.
- Stylesheets: Some L&Fs (like FlatLaf) support theme files or keys you can tweak without writing UI code.
Example changing a default color:
UIManager.put("Button.background", new Color(200, 220, 255));
Apply changes and update UI tree for visible effect.
Handling Issues & Compatibility
- Not all L&Fs support every UI property — test the major components.
- Look for platform-specific class names; using UIManager.getInstalledLookAndFeels() avoids naming errors.
- Some L&Fs may change component sizes — use proper layout managers and test on different DPI settings.
- If components don’t update after setLookAndFeel, call SwingUtilities.updateComponentTreeUI(window) for each top-level window, then revalidate/repaint.
Accessibility and Theming Best Practices
- Ensure sufficient contrast and scalable fonts for accessibility.
- Provide easy access to theme switching in settings, and restore previous selection on startup.
- Avoid hardcoding colors or fonts in component painting; rely on UIManager defaults so themes apply consistently.
Example: Full-featured L&F Selector Panel
A selector panel typically:
- Lists available L&Fs (installed + detected third-party).
- Shows preview area reflecting choices immediately.
- Includes “Apply”, “Save as default”, and “Reset to system” actions.
- Optionally allows tweaking individual UI keys (font, accent color).
Design considerations:
- Load third-party L&F classes lazily to avoid ClassNotFoundExceptions.
- Validate selected L&F by trying to set it in a try/catch and reverting on failure.
Summary
Using a Java Look and Feel Selector improves user experience by letting users switch themes at runtime. Key steps:
- Enumerate available L&Fs.
- Set chosen L&F with UIManager.setLookAndFeel.
- Update component tree UI and persist selection.
- Consider third-party L&Fs and UIDefaults tweaks for richer themes.
Switching themes is low-risk when implemented with proper exception handling and persistence; it makes Swing apps feel modern and user-friendly.
Leave a Reply