Некоторые глифы FontAwesome не отображаются в кнопках Java Swing JToolBar

У меня возникла проблема с отображением определенных глифов из коллекции FontAwesome на кнопках в Swing JToolBar. Вот скриншот для иллюстрации (обратите внимание, что верхняя кнопка на панели инструментов с правой стороны не является красивым значком, а вместо этого показывает три пустых прямоугольника):

Снимок экрана, иллюстрирующий проблему

Код для воспроизведения этого (по крайней мере, на моем Mac):

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

}

Я попробовал несколько вещей: (1) Используя разные версии файла FontAwesome.ttf, без изменений; (2) Пробовал разные версии JDK, без изменений; (3) Отображение того же символа в обычном JButton, это работает, как вы можете видеть на следующем снимке экрана (так что это явно не какая-то проблема с файлом шрифта):

Снимок экрана, показывающий, как это работает в обычном JButton

Я тестировал на Mac без Retina, и все работает, поэтому мне интересно, связано ли это с дисплеем Retina. Если у кого-то есть какие-либо предложения, я был бы рад услышать от вас, спасибо.

Код только для примера JButton (который отлично работает):

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

}

person David Gilbert    schedule 28.08.2014    source источник
comment
JTollBar использует BoxLayout (минимальный, максимальный и предпочтительный размер, предпочтительный размер используется для LayoutManager), тогда есть все возможное в случае, если Font не может вернуть правильную ширину, та же проблема может быть с использованием FlowLayout для JFrame (только PreferredSize) , добавлен тег OSX для TrashGod   -  person mKorbel    schedule 28.08.2014
comment
увидеть разницу в В случае, если шрифт установлен в родной ОС и загружен во время выполнения, по умолчанию нет проблем с тестированием (в пикселях:-) ширины строки с помощью SwingUtilities#computeStringWidth(FontMetrics fm, String str), т.е.   -  person mKorbel    schedule 28.08.2014
comment
кстати, и Retina не примерно в 2 раза больше пикселей, чем действительно используется GPU для контекста рендеринга, настройки эффективного разрешения в пикселях   -  person mKorbel    schedule 28.08.2014
comment
В первой программе я изменил создание button1 на JButton button1 = new JButton(   ); и символ печатается правильно дважды, но искажается для третьего. Для этого я отправил отчет об ошибке в Oracle.   -  person David Gilbert    schedule 28.08.2014
comment
Извините, нет ретина-дисплея. Любая помощь здесь?   -  person trashgod    schedule 28.08.2014
comment
Определенно стоит попробовать, но изменение менеджера компоновки панели инструментов на FlowLayout, к сожалению, не изменило результат (кроме того, что значки работали горизонтально, конечно).   -  person David Gilbert    schedule 28.08.2014
comment
@David Gilbert (прежде чем написать на BugParade - это все еще Sun :-), вам нужно знать количество пикселей, используемых для PreferredSize, к сожалению, ошибок с TextLayout или измерения с использованием 3-го. Шрифты для вечеринок там не принимаются, просто очень хороший улов   -  person mKorbel    schedule 29.08.2014
comment
В качестве обходного пути вы можете отображать глифы напрямую, как показано здесь, или в реализации Icon, как показано здесь.   -  person trashgod    schedule 29.08.2014


Ответы (1)


Я думаю, что проблема в ComponentUi
В специальных средствах: ToolbarUi или ButtonUi (-Реализация).

ToolbarUi (и ButtonUi) – это абстрактные классы, реализованные в выбранном вами LookAndFeel.
Реализация может быть совершенно разной для каждого LookAndFeel.
Некоторые реализации игнорируют некоторые "пользовательские" настройки, такие как например Шрифт или Цвет.

JButtons может использовать другую реализацию пользовательского интерфейса, чем кнопки, которые добавляются в JToolBars!
И эта реализация может игнорировать ваши настройки шрифта.

См., например, реализацию ButtonUi (только часть) в 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;
           }
       }
...

Здесь вы можете увидеть различное поведение, когда MetalUtils.isToolbarButton

Вы должны проверить поведение своей реализации LookAndFeel.
(Возможно, есть и другая реализация, в зависимости от разрешения экрана)

person Ben    schedule 31.08.2014
comment
Я думаю, вы правы, что, вероятно, дело в плотности экрана — пользовательский интерфейс может искать другой глиф, основанный на удвоенной плотности экрана Retina. Есть ли другой или более новый файл FontAwesome ttf для дисплеев с высокой плотностью? - person Steve K; 04.09.2014
comment
Я сомневаюсь, что проблема связана с файлом TTF, поскольку в примере с JButton все глифы отображаются правильно. - person David Gilbert; 05.09.2014
comment
Конечно, делегат пользовательского интерфейса является фактором. Я пробовал использовать Metal и Nimbus LAF, и значок отображается правильно, так что проблема только во внешнем виде системы (Mac). - person David Gilbert; 05.09.2014
comment
Возможно это похожая проблема, как у меня: stackoverflow.com/q/25663165/3887073 (похоже, что используется другой шрифт, чем ожидалось) - person Ben; 05.09.2014
comment
@DavidGilbert: считаете ли вы, что этот ответ адекватно отвечает на вопрос о награде? - person Hovercraft Full Of Eels; 06.09.2014
comment
Это указывает в правильном направлении, но я не считаю это окончательным ответом. Тем не менее, я не думаю, что мы получим более точную информацию, пока кто-нибудь из Oracle не просмотрит представленный мной отчет об ошибке. Так что я приму это как ответ. - person David Gilbert; 06.09.2014
comment
@DavidGilbert: Достаточно честно, и я тоже. Баунти доставлен. - person Hovercraft Full Of Eels; 07.09.2014
comment
Вот отчет об ошибке OpenJDK, который я подал: bugs.openjdk.java.net/browse/JDK -8056982 - person David Gilbert; 17.10.2014