9

I'm having a problem displaying certain glyphs from the FontAwesome collection in buttons in a Swing JToolBar. Here is a screenshot to illustrate (notice that the top button in the toolbar on the right hand side is not a nice icon but instead shows three empty rectangles):

Screenshot to illustrate the problem

The code to reproduce this (at least on my Mac) is:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Font;![enter image description here][2]
import java.awt.FontFormatException;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JToolBar;

public class TestFontAwesome {

    public static void main(String[] args) {
        new TestFontAwesome();
    }

    public TestFontAwesome() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try (InputStream is = TestFontAwesome.class.getResourceAsStream("/fontawesome-webfont_old.ttf")) {
                    Font font = Font.createFont(Font.TRUETYPE_FONT, is);
                    font = font.deriveFont(Font.PLAIN, 24f);

                    JToolBar toolBar = new JToolBar(JToolBar.VERTICAL);
                    JButton button1 = new JButton("\uf00e");
                    button1.setFont(font);
                    toolBar.add(button1);
                    JButton button2 = new JButton("\uf01e");
                    button2.setFont(font);
                    toolBar.add(button2);
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new JButton("Irrelevant content..."));
                    frame.add(toolBar, BorderLayout.EAST);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException | FontFormatException exp) {
                    exp.printStackTrace();
                }
            }
        });
    }

}

I tried a few things: (1) Using different versions of the FontAwesome.ttf file, no change; (2) Trying different JDK versions, no change; (3) Displaying the same character in a regular JButton, this works as you can see in the following screenshot (so this is clearly not some issue with the font file):

Screenshot to show it works in a regular JButton

I tested on a non-Retina Mac and everything works, so I wonder if this is something specific to the Retina display. If anyone has any suggestions I'd appreciate hearing from you, thanks.

The code for the JButton only example (that works fine) is:

import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontFormatException;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.JButton;
import javax.swing.JFrame;

public class TestFontAwesome2 {

    public static void main(String[] args) {
        new TestFontAwesome2();
    }

    public TestFontAwesome2() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try (InputStream is = TestFontAwesome.class.getResourceAsStream("/fontawesome-webfont_old.ttf")) {
                    Font font = Font.createFont(Font.TRUETYPE_FONT, is);
                    font = font.deriveFont(Font.PLAIN, 24f);

                    JButton button1 = new JButton("\uf00e");
                    button1.setFont(font);
                    JButton button2 = new JButton("\uf01e");
                    button2.setFont(font);
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new FlowLayout());
                    frame.add(new JButton("Irrelevant content..."));
                    frame.add(button1);
                    frame.add(button2);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException | FontFormatException exp) {
                    exp.printStackTrace();
                }
            }
        });
    }

}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
David Gilbert
  • 4,427
  • 14
  • 22
  • 1
    JTollBar uses BoxLayout (min, max and preferred size, preferred size is used for LayoutManager), then there is everything possible in the case that Font can't returns proper widht, the same issue can be by using FlowLayout for JFrame (only PreferredSize), added osx tag for trashgod – mKorbel Aug 28 '14 at 12:06
  • [see difference in the case that Font is instaled in Native OS and loaded at runtime](http://stackoverflow.com/questions/18461331/ttf-and-otf-versions-of-source-sans-pro-are-differently-displayed-in-swing-nimb), by default there isn't an issue to test (in pixels:-) for String widht by using SwingUtilities#computeStringWidth(FontMetrics fm, String str), e.i. – mKorbel Aug 28 '14 at 12:14
  • btw and Retina isn't about 2times more pixels as is really used by GPU for rendering context, setting for effective resolution in pixels – mKorbel Aug 28 '14 at 12:15
  • In the first program, i changed the creation of button1 to JButton button1 = new JButton("\uf00e \uf00e \uf00e "); and the symbol prints correctly twice but is corrupted for the third. I submitted a bug report to Oracle for this. – David Gilbert Aug 28 '14 at 15:18
  • Sorry, no retina display. Any help [here](http://stackoverflow.com/a/14456356/230513)? – trashgod Aug 28 '14 at 19:45
  • Definitely worth a try, but changing the toolbar layout manager to FlowLayout didn't change the result unfortunately (apart from making the icons run horizontally, of course). – David Gilbert Aug 28 '14 at 19:56
  • @David Gilbert (before anthing on BugParade - is still Sun:-) you need to know the numbers of pixels used for PreferredSize, unfortunatelly bugs with TextLayout or measuring by using 3rd. party Font(s) aren't accepted there, just the very nice catch – mKorbel Aug 28 '14 at 20:14
  • As a workaround, you can render the glyph(s) directly, as seen [here](http://stackoverflow.com/a/4151403/230513) or in an implementation of `Icon`, as seen [here](http://stackoverflow.com/a/2834484/230513). – trashgod Aug 29 '14 at 01:10

1 Answers1

4

i think the problem is the ComponentUi
Means in special: ToolbarUi or ButtonUi (-Implementation).

ToolbarUi (and ButtonUi) are abstract classes, which are implemented in your selected LookAndFeel.
The Implementation can be totally different for each LookAndFeel.
Some Implementations do ignore some "user" settings like e.g Font or Color.

JButtons can use a different Ui-Implementation than Buttons which are added to JToolBars!
And this Implementation may ignore your Font settings.

See for example ButtonUi Implementation (only part of) in MetalLookAndFeel

public void update(Graphics g, JComponent c) {
   AbstractButton button = (AbstractButton)c;
   if ((c.getBackground() instanceof UIResource) &&
             button.isContentAreaFilled() && c.isEnabled()) {
       ButtonModel model = button.getModel();
       if (!MetalUtils.isToolBarButton(c)) {
           if (!model.isArmed() && !model.isPressed() &&
                   MetalUtils.drawGradient(
                   c, g, "Button.gradient", 0, 0, c.getWidth(),
                   c.getHeight(), true)) {
               paint(g, c);
               return;
           }
       }
...

Here you can see the different behaviour when MetalUtils.isToolbarButton

You have to check your LookAndFeel Implementation behaviour.
(Maybe there is also a different Implementation, depending the screen resolution)

Ben
  • 3,378
  • 30
  • 46
  • I think you're right that it's probably something about the screen density - the UI may be looking for a different glyph based on the Retina's doubled screen density. Is there a different or newer FontAwesome ttf file for high-density displays? – Steve K Sep 04 '14 at 02:22
  • I doubt that the issue is with the TTF file, since all the glyphs display correctly in the JButton example. – David Gilbert Sep 05 '14 at 05:00
  • 1
    Certainly the UI delegate is a factor. I tried with the Metal and Nimbus LAFs and the icon displays correctly, so it is only the (Mac) system look & feel that has the issue. – David Gilbert Sep 05 '14 at 05:09
  • **Maybe** it is a similar poblem, like mine: http://stackoverflow.com/q/25663165/3887073 (it looks like a different Font than expected is used) – Ben Sep 05 '14 at 06:56
  • @DavidGilbert: do you feel that this answer adequately answers the question for the bounty? – Hovercraft Full Of Eels Sep 05 '14 at 21:10
  • It points in the right direction but I don't consider it a definitive answer. That said, I don't think we'll get any better info until someone at Oracle can look at the bug report I submitted. So I'll accept this as the answer. – David Gilbert Sep 05 '14 at 23:20
  • @DavidGilbert: Fair enough, and so will I. Bounty delivered. – Hovercraft Full Of Eels Sep 06 '14 at 21:25
  • Here is the OpenJDK bug report I filed: https://bugs.openjdk.java.net/browse/JDK-8056982 – David Gilbert Oct 17 '14 at 13:06