How to Use Java Look And Feel Selector to Change Your App’s Theme

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:

  1. Add the library jar to classpath (Maven/Gradle is preferred).
  2. Include the L&F class name in your selector options.
  3. 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.

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.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *