开发者

How to change the default font size in the Swing GTK LookAndFeel?

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!


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.


There appears to be no way to set the default font size. However, the bug referenced in the question has since been fixed, so the need to do this is now moot.


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


I lost a lot of time figuring out how to make our app decent on ubuntu and I came to this hack. I have tried like someone suggested to extend GTKLookAndFeel but since it uses many native calls to GTKEngine and I realized it was not viable. I hope this helps

Just after setting the look and feel call my hack checkGTKLookAndFeel() it reduces the font standard of two points :

UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
try {
    InvoicexUtil.checkGTKLookAndFeel();
} catch (Exception e) {
    e.printStackTrace();
}

public static void checkGTKLookAndFeel() throws Exception {
    LookAndFeel look = UIManager.getLookAndFeel();
    if (!look.getID().equals("GTK")) return;

    new JFrame();
    new JButton();
    new JComboBox();
    new JRadioButton();
    new JCheckBox();
    new JTextArea();
    new JTextField();
    new JTable();
    new JToggleButton();
    new JSpinner();
    new JSlider();
    new JTabbedPane();
    new JMenu();
    new JMenuBar();
    new JMenuItem();

    Object styleFactory;
    Field styleFactoryField = look.getClass().getDeclaredField("styleFactory");
    styleFactoryField.setAccessible(true);
    styleFactory = styleFactoryField.get(look);

    Field defaultFontField = styleFactory.getClass().getDeclaredField("defaultFont");
    defaultFontField.setAccessible(true);
    Font defaultFont = (Font) defaultFontField.get(styleFactory);
    FontUIResource newFontUI;
    newFontUI = new FontUIResource(defaultFont.deriveFont((float)(defaultFont.getSize() - 2f)));
    defaultFontField.set(styleFactory, newFontUI);

    Field stylesCacheField = styleFactory.getClass().getDeclaredField("stylesCache");
    stylesCacheField.setAccessible(true);
    Object stylesCache = stylesCacheField.get(styleFactory);
    Map stylesMap = (Map) stylesCache;
    for (Object mo : stylesMap.values()) {
        Field f = mo.getClass().getDeclaredField("font");
        f.setAccessible(true);
        Font fo = (Font)f.get(mo);
        f.set(mo, fo.deriveFont((float)(fo.getSize() - 2f)));
    }
}

call the various swing components constructor to initialize GTK styles. not very elegant but it works

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜