Java: использование deriveFont не изменяет размер шрифта

#java #graphics #fonts #size

#java #графика #шрифты #размер

Вопрос:

Я загружаю пользовательский шрифт (из ttf-файла) в свой проект и использую deriveFont (float f) для изменения размера. Однако размер фактически не устанавливается (застрял на 1). Вот мой код:

 public static void main(String[] args) {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    try {
        Font mont =
                Font.createFont(
                        Font.TRUETYPE_FONT,
                        new File(System.getProperty("user.dir")   "/data/Montserrat-MediumItalic.ttf"))
                        .deriveFont(20f);
        ge.registerFont(mont);

        Arrays.stream(ge.getAllFonts())
                .filter(font -> font.getFontName().contains("Mont"))
                .forEach(font -> System.out.println(font.getFontName()   ", Size: "   font.getSize()));

    } catch (FontFormatException | IOException e) {
        e.printStackTrace();
    }
}
  

вывод:
Montserrat Medium Italic, Size: 1

примечание: замена font.getSize() на font.getSize2D prints 1.0 .

Новое: использование decode:

Сейчас я использую это

 Font test = Font.decode("Montserrat Medium Italic-ITALIC-20");
  

(исправлен класс, который не загружается)

Обновление 2:

эта строка: Font mont = Font.createFont(Font.ITALIC, new File(System.getProperty("user.dir") "/data/Montserrat-MediumItalic.ttf"));
выдает IllegalArgumentException: font format not recognized

Комментарии:

1. ge.registerFont(mont) Возвращается true ? Получаете ли вы какие-либо выходные данные, если попытаетесь перечислить шрифт перед его регистрацией?

2. Что mont.getSize() возвращает?

3. @JohnBollinger это (часть) javadocs для getSize(): Returns the point size of this <code>Font</code>, rounded to an integer.

4. Кроме того, register возвращает значение true. Помещение выходных данных перед регистром приводит к отсутствию выходных данных вообще.

5. Я могу прочитать документацию Font.getSize() сам, спасибо. И сделал. Я спросил о результате конкретного выражения, включающего вызов этого метода.

Ответ №1:

Однако размер фактически не устанавливается (застрял на 1).

Это кажется маловероятным. Я попросил прямого подтверждения в комментарии к вопросу («Что mont.getSize() возвращает?» — ой, какая смущающе плохая грамматика), но пока вы не ответили. Я достаточно уверен, что если вы проверите, вы увидите, что mont.getSize() размер соответствует запрошенному вами размеру.

Альтернативное объяснение вашего наблюдаемого поведения легко доступно. Вы используете GraphicsEnvironment.getAllFonts() для составления отчета о зарегистрированных шрифтах, но, согласно его документации, этот метод

Возвращает массив, содержащий экземпляр размера в одну точку всех шрифтов, доступных в этой графической среде.

(Выделено мной.)

Другой ответ и особенно комментарии к нему предполагают, что Font объекты, возвращаемые GraphicsEnvironment.getAllFonts() , могут отличаться и другими способами от соответствующих Font экземпляров, переданных GraphicsEnvironment.registerFont() . Хотя, насколько я вижу, такие изменения не документированы, они согласуются с предполагаемым использованием Font объектов, полученных из GE, как описано в getAllFonts() документах:

Типичным использованием было бы разрешить пользователю выбирать определенный шрифт. Затем приложение может изменять размер шрифта и устанавливать различные атрибуты шрифта, вызывая метод deriveFont в выбранном экземпляре.

Они продолжают говорить, что

Если шрифт в этой графической среде имеет несколько программируемых вариантов, в массив возвращается только один экземпляр этого шрифта, а другие варианты должны быть получены приложением.

Я не уверен, что «несколько программируемых вариантов» означают атрибуты, которые могут быть изменены при выводе одного Font объекта из другого (ибо тогда у какого шрифта не было бы программируемых вариантов?), Но ясно, что getAllFonts() это не механизм для считывания точных Font объектов, ранее представленных GraphicsEnvironment.registerFont() . Эти объекты могут даже не сохраняться как таковые.

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

Комментарии:

1. Спасибо за подробный ответ. Я печатаю mont.getSize() сразу после mont.deriveFont(20f) , и он печатает «1»

2.@PhaseRush, если getSize() метод Font экземпляра, полученный с помощью вызова deriveFont(20f) , возвращает 1, значит, что-то сильно не так. Однако я не могу не заметить, что ваш комментарий описывает тестирование чего-то другого. mont.deriveFont(20f) создает и возвращает новый Font экземпляр; он не изменяет тот, на котором он вызывается. Таким образом, mont.getSize() после этого должно быть возвращено то же значение, что и непосредственно перед этим.

3. @PhaseRush Вы не печатаете mont.getSize() в коде в вашем вопросе.

4. хорошо, спасибо, я исправил свою проблему, выполнив 2 вещи. 1. обновлен размер, изменив шрифт mont = bunchOfFuncs(); mont.derive(20f); на шрифт mon = sameBunchOfFuncs().derive() 2. исправлен недопустимый аргумент, изменив имя файла ttf на «Montserraft.ttf». Теперь, когда мне нужен шрифт, я использую Font.decode(Montserrat-PLAIN-20), и это работает

Ответ №2:

Я думаю, я знаю, в чем проблема. Когда вы вызываете ge.registerFont(mont) , он делает именно это, он регистрирует базовый шрифт, без изменений в объекте font. deriveFont() Функция изменяет только состояние текущего объекта font, но не может изменить фактический шрифт. Когда вы регистрируете шрифт, он регистрируется с размером 1. Если вы напечатаете размер всех других шрифтов, вы обнаружите, что они также имеют значение по умолчанию 1. Я не думаю, что вы можете зарегистрировать шрифт с пользовательским размером по умолчанию или переопределить размер по умолчанию Font.getFont() . Когда вы получаете шрифт с помощью Font.getFont() , он всегда будет иметь размер по умолчанию 12 (из спецификации).

Если вам нужно, чтобы шрифт был специально отформатирован, я бы предложил создать статическую переменную класса:

 Font MontMediumItalic_20;
  

Затем загрузите шрифт один раз, либо в загрузчике ресурсов, либо в конструкторе, и примените к нему все изменения.

В качестве альтернативы вы также можете использовать Font.decode()

Пожалуйста, дайте мне знать, если вам нужна какая-либо помощь.

Комментарии:

1. Что за «базовый шрифт»? Font Класс имеет концепцию получения одного шрифта из другого, но не имеет представления об одном, лежащем в основе другого, и, конечно, он не предоставляет средств для получения такого базового шрифта. Более того, GraphicsEnvironment.registerFont() документы, которые он может использовать для регистрации только созданных шрифтов, таких как те, которые получены с помощью Font.deriveFont() , что не имело бы смысла, если бы то, что он регистрирует, действительно было каким-то родовым, оригинальным, базовым шрифтом.

2. С другой стороны, вполне вероятно, что GraphicsEnvironment будет регистрировать шрифты стандартного размера, например, 1 точка, хотя в документах не приводится никаких оснований ожидать такого поведения.

3. @Jhon под базовым шрифтом don’t я имел в виду базовый шрифт, загруженный непосредственно из файла .tff, без каких-либо изменений, за исключением нормализации размера шрифта до 1.

4. Опять же, Font класс не имеет представления о такой вещи, и это, похоже, не согласуется с требованием, чтобы Font зарегистрированные в GraphicsEnvironment быть созданными .

5. @John Я согласен, что это deriveFont противоречит интуиции, но нет смысла регистрировать шрифт нестандартного размера, потому что согласно спецификации любой вызов Font.decode или Font.getFont вернет либо указанный размер, либо стандартный размер 12.