views:

127

answers:

2

Is there a way to change the default font size in the Swing GTK LaF?

The GTK LaF seems to assume 72dpi, so all the fonts are only 3/4 of the size they should be when using a 96dpi screen. See this Fedora bug for details. I'd like to find a workaround in the meantime, while I wait for the fix.

I've already tried resetting the font size via UIDefaults, as recommended here, for example, but (as also noted there) the GTK LaF appears to ignore this.

I could build a widget factory that would also set the desired font size for creating all of my Swing widgets, but that's going to be massively invasive, so I'd like to avoid that route if there's any other way.

Edit: The following doesn't work:

public class GTKLaF extends com.sun.java.swing.plaf.gtk.GTKLookAndFeel {
  @Override
  public UIDefaults getDefaults() {
    final float scale = 3f;

    final UIDefaults defaults = super.getDefaults(); 

    final Map<Object,Object> changes = new HashMap<Object,Object>();

    for (Map.Entry<Object,Object> e : defaults.entrySet()) {
      final Object key = e.getKey();
      final Object val = e.getValue();

      if (val instanceof FontUIResource) {
        final FontUIResource ores = (FontUIResource) val;
        final FontUIResource nres =
          new FontUIResource(ores.deriveFont(ores.getSize2D()*scale));
        changes.put(key, nres);
        System.out.println(key + " = " + nres);
      } 
      else if (val instanceof Font) {
        final Font ofont = (Font) val;
        final Font nfont = ofont.deriveFont(ofont.getSize2D()*scale);
        changes.put(key, nfont);
        System.out.println(key + " = " + nfont);
      }
    }

    defaults.putAll(changes);

    return defaults;
  }
}

You might think this would print at least a dozen key-value pairs, but it prints only one: TitledBorder.font. Apparently the other font properties are not supplied by the GTLLookAndFeel, but come from someplace else!

A: 

There is something wrong with the code you linked.UIDefaults.get(key) function doesnt have to return a Font instance. It may be a javax.swing.plaf.FontUIResource instance. Following code snippet finds all installed look and feels, than changes all fonts sizes at a ratio of scale

float scale=1.1f;
UIManager.LookAndFeelInfo looks[] = UIManager.getInstalledLookAndFeels();

for (UIManager.LookAndFeelInfo info : looks) {

    //if you want to change LaF to a spesific LaF,such as "GTK"
    //put here a if statement like:
    //if(info.getClassName().contains("GTK"))
    UIManager.setLookAndFeel(info.getClassName());

    UIDefaults defaults = UIManager.getDefaults();
    Enumeration newKeys = defaults.keys();

    while (newKeys.hasMoreElements()) {
        Object obj = newKeys.nextElement();
        Object current = UIManager.get(obj);
        if (current instanceof FontUIResource) {
            FontUIResource resource = (FontUIResource) current;
            defaults.put(obj, new FontUIResource(resource.deriveFont(resource.getSize2D()*scale)));
            // System.out.printf("%50s : %s\n", obj,  UIManager.get(obj));
        } else if (current instanceof Font) {
            Font resource = (Font) current;
            defaults.put(obj, resource.deriveFont(resource.getSize2D()*scale));
            // System.out.printf("%50s : %s\n", obj,  UIManager.get(obj));
        }
    }
}

I find something about the GTK LaF problem a book, Java Examples in a Nutshell, Third Edition. Take a look at it here

feridcelik
This does not work. For the GTK LaF, it makes no difference to what I set the scale factor to---this code has no noticeable effect.
uckelman
@uckelman Does it work on other LaFs?
feridcelik
The call to UIManager.getInstalledLookAndFeels() seems to cause a catastrophic crash of X, somehow---the machine locks up hard. If I remove that and the outer loop, your code does work for the Metal LaF.
uckelman
Answer updated, There is a link at the bottom of the answer explaining GTK problem. Please try it and let me know if it works.
feridcelik
That link is about making sure that the system knows about the GTL LaF. That's not the problem I'm facing. When I run with `-Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel` set, I do get the GTK LaF as the installed LaF. `UIManager.getSystemLookAndFeelClassName()` returns `com.sun.java.swing.plaf.gtk.GTKLookAndFeel` in that case. The problem is that the GTK LaF just ignores the keys I put into `UIManager`.
uckelman
+1  A: 

My suggestion is to create your own subclass of GTKLookAndFeel and use that.

In your subclass, I'd probably override getDefaults(). In your getDefaults() you can get the UIDefaults that GTKLookAndFeel was going to return and adjust them if necessary. (By wrapping or subclassing them and overriding the UIDefaults.getFont methods.)

Get the current DPI with

int dpi = Toolkit.getDefaultToolkit().getScreenResolution();

and if it's not 72 you can change the font size accordingly.

Edit: the link you posted doesn't work, I believe because GTKLookAndFeel overrides the methods involved and doesn't let any defaults from its ancestors to pass through. Overriding it in turn should allow you to circumvent that problem.

bemace
See my edit to the original question. Overriding `getDefaults()` doesn't work because the keys aren't there.
uckelman
Man, this must be one poorly designed look-and-feel. While I haven't looked at the source code, I'm starting to feel like they just hard-coded the values. As a last resort, you could copy the GTKLookAndFeel code into your own class and hack something in.
bemace
Yeah, I think it's rather a steaming pile. I gave you the bounty because (1) time was almost up, and (2) you came closest to an answer. (My suspicion is that getting this right will require overriding more methods, possibly in some other classes in `com.sun.java.swing.plaf.gtk`.)
uckelman