4

I want to calculate the Font Size due to a width value.

//Custom Font
Font.loadFont(Fonts.class.getResourceAsStream("/font/bignood/bignoodletoo.ttf"), 10)
String text = "Hello World";
Double width = 100;

Similiar SO Question to Java AWT

Similar SO Question to Java AWT 2


Edit: Use case

Think about a button that have a text "PLAY MONEY"¹. Now I will translate the text to PT_BR and it calls now "DINHEIRO FICTICIO"². As you can see, the word² is bigger than word¹, so if you set the same Font Size then you gonna see DINHEIRO FIC... inside the button.

So the mission here is get the width value of the Button, get the text and apply the Font Size to fit the full text inside the Button, whenever I change the text.

Marckaraujo
  • 7,422
  • 11
  • 59
  • 97
  • 1
    Can you be a little more specific on what you want to get the width of (Like a Scene or something), and how large you want the font to be compared to it? – Austin Jun 19 '17 at 22:52
  • @Austin, the width I will get from button, label e etc.. Any object that have a text. The text with the custom font needs to fit the exactly width value. – Marckaraujo Jun 19 '17 at 22:57
  • The text needs to fit or the `Button` / `Label`? The latter 2 include margins for the text... – fabian Jun 20 '17 at 05:21
  • @fabian, the text needs to fit any width value. I will update the question with an use case. – Marckaraujo Jun 20 '17 at 13:31

1 Answers1

6

Below is a findFontSizeThatCanFit() method (and demo) that can be useful for this.

(See it in action online)

public class FxFontMetrics {
    public static void main(String[] args) {
        int maxWidth = 100;
        System.out.println("# Text -> Font size that can fit text under " + maxWidth + " pixels");
        Stream.of(
                "DINHEIRO FICTICIO",
                "Dinheiro ficticio",
                "PLAY MONEY",
                "Play money",
                "Devise factice qui compte pour du beurre")
                .forEach(text -> {
                    double size = findFontSizeThatCanFit(Font.font("dialog", 45), text, maxWidth);
                    System.out.println(text + " -> " + size);
                });
    }

    private static double findFontSizeThatCanFit(Font font, String s, int maxWidth) {
        double fontSize = font.getSize();
        double width = textWidth(font, s);
        if (width > maxWidth) {
            return fontSize * maxWidth / width;
        }
        return fontSize;
    }

    private static double textWidth(Font font, String s) {
        Text text = new Text(s);
        text.setFont(font);
        return text.getBoundsInLocal().getWidth();
    }
}

It prints:

# Text -> Font size that can fit text under 100 pixels
DINHEIRO FICTICIO -> 10.475703324808185
Dinheiro ficticio -> 12.757739986295396
PLAY MONEY -> 15.587183195068118
Play money -> 17.152428810720266
Devise factice qui compte pour du beurre -> 4.795354500327807
Hugues M.
  • 19,846
  • 6
  • 37
  • 65
  • It works, but it is "too expansive for what it is" (as I have to create a new Font/text object at every iteration...). I was expecting something with `GraphicsContext` as used in the linked `SO question 1` for Java AWT. – Marckaraujo Jun 30 '17 at 14:03
  • Ah, yes, we can avoid the loop by using a division (if non-round values are not allowed or desired, use `Math.floor()`). I edited the answer. This still involves creation of a dummy `Text` node, but no need for new `Font` objects, right. But this is assuming the font renders a given text in a way that is proportional to its size, but I'm not sure it's always linear in reality :-/ – Hugues M. Jun 30 '17 at 14:23
  • You could use a `private static` `Text` object, inside `textWidth(...)`, instead of creating a new `Text` each call, right? – Kröw Jul 22 '18 at 05:44