Java: Altering UI fonts (Nimbus) doesn't work!
Asked Answered
A

6

8

I'm referring to this Nimbus reference.

I tried to set global Font to be slightly larger:

UIManager.put("defaultFont", new Font(Font.SANS_SERIF, 0, 16));

...works only for the menu but nothing else (buttons, labels).

I tried to change labels and buttons fonts with

UIManager.put("Button.font", new Font(Font.SANS_SERIF, 0, 16));
UIManager.put("Label.font", new Font(Font.SANS_SERIF, 0, 16));

but the font remains.

The only thing that worked for me was deriving a font:

someButton.setFont(someButton.getFont().deriveFont(16f));

But this is not an option, since this must be done for each element manually.

Note, that deriving a font for UIManager doesn't work either:

UIManager.put("Label.font",
    UIManager.getFont("Label.font").deriveFont(16f));

I tested everything under Linux and Windows: same behavior.

I just can't understand how an API can be so messy. If a method is called setFont(..) then I expect it to set the font. If this method fails to set the font in any thinkable circumstances, then it should be deprecated.

EDIT:
The problem not only applies to Nimbus, but also to the default LAF.

Anastasiaanastasie answered 4/6, 2009 at 8:54 Comment(5)
Did you try to call SwingUtilities.updateComponentTreeUI(frame); after updating UI defaults?Rolfe
That code won't even compile; there's no Font constructor that takes a float as the third parameter.Dogcatcher
That code was example code which doesn't event need to compile ;) In real code I had usages of static variables, and as I removed them to do this example, I was looking at deriveFont(..) which takes float.Anastasiaanastasie
SwingUtilities.updateComponentTreeUI(frame) doesn't help eitherAnastasiaanastasie
Actually Nimbus has the "Label.font" property but it is not working when the user defines a custom value. This can be one more of Nimbus/Synth bugs. I had problems like these before that's why I choose Metal/Basic has base for a custom LAF.Rhaetian
F
7

This works with JDK6 and JDK7. Copy+paste and have fun ;)

Note: for JDK6, change
javax.swing.plaf.nimbus to
com.​sun.​java.​swing.​plaf.​nimbus.

Code

import java.awt.*;
import java.lang.reflect.*;
import javax.swing.*;
import javax.swing.plaf.nimbus.*;

public class Main {

 public static void main(String[] args)
   throws InterruptedException, InvocationTargetException {

  SwingUtilities.invokeAndWait(new Runnable() {

   @Override
   public void run() {
    try {
     UIManager.setLookAndFeel(new NimbusLookAndFeel() {

      @Override
      public UIDefaults getDefaults() {
       UIDefaults ret = super.getDefaults();
       ret.put("defaultFont",
         new Font(Font.MONOSPACED, Font.BOLD, 16)); // supersize me
       return ret;
      }

     });

     new JFrame("Hello") {

      {
       setDefaultCloseOperation(EXIT_ON_CLOSE);
       setLayout(new FlowLayout(FlowLayout.LEFT));

       setSize(500, 500);
       setLocationRelativeTo(null);

       add(new JLabel("someLabel 1"));
       add(new JButton("someButton 1"));
       add(new JLabel("someLabel 2"));
       add(new JButton("someButton 2"));

       setVisible(true);
      }

     };     
    } catch (Exception ex) {
     throw new Error(ex);
    }
   }

  });
 }

}
Fitton answered 4/4, 2010 at 23:16 Comment(1)
Thanks, of all the hints I found this was the only one that worked around the Nimbus bugs.Cay
P
6

The nimbus defaults are lazy created so setting 'defaultFont' before the screen is painted, will add the font to the parent defaults, and not to the nimbus defaults.

Workaround: force nimbus to initialize the defaults and set then the defaults:

NimbusLookAndFeel laf = new NimbusLookAndFeel();
UIManager.setLookAndFeel(laf);
laf.getDefaults().put("defaultFont", new Font("Monospaced", Font.BOLD, 12));

Note: this code is more efficient then overriding getDefaults(), as suggested above.

Paraclete answered 6/10, 2011 at 9:37 Comment(0)
S
1

One thing that amazes me to this day is that the LaF setters [setFont, setBackground, etc] do not actually set real properties. The spec says that LaFs are allowed to ignore user set fonts, colors, etc. This is why GTKLaF is completely broken. It uses the system gtk theme settings, not the programmer's settings. IIRC Nimbus has a separate, package private class that contains defaults (NimbusDefaults?) and can't be easily accessed.

I suggest never using GTK or Nimbus LAF if you plan on customizing the look in any way.

A quick google search turns up this for GTK

A discussion about these problems in nimbus can be found here.

Stroke answered 4/6, 2009 at 12:48 Comment(2)
Well, setting those properties actually WORK for me! I quote my question: The only thing that worked for me was deriving a font: someButton.setFont(someButton.getFont().deriveFont(16f));Anastasiaanastasie
But doing someComponent.setFont(..) is not an option, since this way, I had to do it for each and every component! == copy&paste-code.Anastasiaanastasie
E
1

Wrap your Font with FontUIResource. I had the exact same problem with UIManager colors and ColorUIResource fixed everything. Without digging through the JDK, I think there are some places where components expect (read: check via instanceof) for UIResources (maybe someone can confirm this)

Emelineemelita answered 4/6, 2009 at 12:57 Comment(2)
meh, it was worth a shot. Keep it in mind if you want to change colors.Emelineemelita
Changing colors works perfectly using UIManager.put("nimbusBase", new Color(someColor));Anastasiaanastasie
P
1

The answer in a single line of code (assuming you have already set Nimbus LaF):

UIManager.getLookAndFeelDefaults().put("defaultFont", new Font(Font.SANS_SERIF, 0, 20));

Of course, you need to call this before you create any GUI components, i.e. right in your main just after setting Nimbus LaF.

Phew answered 18/4, 2013 at 8:7 Comment(0)
R
0

Java LAF API is a little bit clumsy, but there is nothing better than check the source code to get your answers.

Note that MetalLookAndFeel and Nimbus are different implementations and the properties for each one doesn't have to be the same.

The following examples use the MetalLookAndFeel.

package com.stackoverflow.laf.font;

import java.awt.Font;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class SetFontExample {

  public static void main(String[] args) {

    SwingUtilities.invokeLater(new Runnable() {
      @Override public void run() {
        UIManager.put("Label.font", new Font(Font.SANS_SERIF, 0, 20));
        try {
          UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
        } catch (Exception e) {
          e.printStackTrace();
        }

        JFrame frame = new JFrame("Set font example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new JLabel("Font test"));
        frame.pack();
        frame.setVisible(true);
      }
    });
  }
}

This works because the property "Label.font" exists on Metal and it uses that property correctly.

You you can check it this way:

package com.stackoverflow.laf;

import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;

public class ListLAFUIDefaults {

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override public void run() {
        try {
          // Choose LAF
          UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
        } catch (Exception e) {
          e.printStackTrace();
        }
        UIDefaults defaults = UIManager.getLookAndFeel().getDefaults();
        System.out.println(defaults);

        // Check a property
        String propertyKey = "defaultFont";
        System.out.println(UIManager.getLookAndFeel().getName() +
            (defaults.containsKey(propertyKey) ? " contains " : " doesn't contain ") +
            "property " + propertyKey);
      }
    });
  }
}
Rhaetian answered 4/6, 2009 at 10:59 Comment(3)
Note: since I'm reading the property before I write it by doing UIManager.put("Label.font", UIManager.getFont("Label.font").deriveFont(16f)); there MUST be such property "Label.font".Anastasiaanastasie
In deed, your example works! But only as long as I don't use Nimbus UI instead of cross platform LAF.Anastasiaanastasie
That's a Nimbus bug. Please check jasperpotts.com/blog/2008/08/nimbus-uimanager-uidefaults/…Rhaetian

© 2022 - 2024 — McMap. All rights reserved.