views:

1562

answers:

4

Hello!

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.

A: 

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);
      }
    });
  }
}
hfernandes
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".
ivan_ivanovich_ivanoff
In deed, your example works! But only as long as I don't use Nimbus UI instead of cross platform LAF.
ivan_ivanovich_ivanoff
That's a Nimbus bug. Please check http://www.jasperpotts.com/blog/2008/08/nimbus-uimanager-uidefaults/#comment-1351
hfernandes
+1  A: 

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.

KitsuneYMG
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));
ivan_ivanovich_ivanoff
ivan_ivanovich_ivanoff
A: 

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)

basszero
Tried this before, didn't work also :(
ivan_ivanovich_ivanoff
meh, it was worth a shot. Keep it in mind if you want to change colors.
basszero
Changing colors works perfectly using UIManager.put("nimbusBase", new Color(someColor));
ivan_ivanovich_ivanoff
+1  A: 

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);
    }
   }

  });
 }

}
java.is.for.desktop