1

I have a javafx gui which contains a text-box. I want to know how I can find the best font-size for the text to be set to.

The text-box cannot be resized to fit the text and the text cannot be truncated/overflow.

During the program, the text-box can change its dimensions and the text can change font (eg. from Arial to Comic Sans), or change the text itself (from single words to paragraphs), and I need to make sure that the text gets resized to fit the text-box.

The text-box can be any node that holds text like label,textFlow,textArea...

I wrote 3 different attempts to try and develop such algorithm but none of them worked.

Main Code:

public class Main extends Application{

    String text = new String("Lorem ipsum dolor sit amet, consectetur adipiscing elit. In scelerisque elit ante, eu lacinia dui molestie quis. Donec consectetur elementum.");



    TextFlow textBox;
    AnchorPane anchorPane;

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

    @Override
    public void start(Stage primaryStage) throws Exception{
        textBox = new TextFlow(new Text(text));
        textBox.setTextAlignment(TextAlignment.CENTER);

        anchorPane = new AnchorPane(textBox);

        AnchorPane.setTopAnchor(textBox,0d);
        AnchorPane.setBottomAnchor(textBox,0d);
        AnchorPane.setRightAnchor(textBox,0d);
        AnchorPane.setLeftAnchor(textBox,0d);


        Scene scene = new Scene(anchorPane);
        primaryStage.setScene(scene);
        primaryStage.show();

        textBox.widthProperty().addListener(new ChangeListener<Number>(){
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue){
                autoSizeTextBoxText();
            }
        });

        textBox.heightProperty().addListener(new ChangeListener<Number>(){
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue){
                autoSizeTextBoxText();
            }
        });
    }

    public void setTextBoxFont(Font font){
        ((Text)textBox.getChildren().get(0)).setFont(font);
        autoSizeTextBoxText();
    }

    public void setTextBoxText(String text){
        ((Text)textBox.getChildren().get(0)).setText(text);
        autoSizeTextBoxText();
    }


    public void autoSizeTextBoxText(){
        Font font = TextAndFontHelper.getOptimalFont(((Text)textBox.getChildren().get(0)).getText(),textBox,((Text)textBox.getChildren().get(0)).getFont());
        System.out.println(font.getSize());
        ((Text)textBox.getChildren().get(0)).setFont(font);
        anchorPane.layout();
        textBox.layout();
    }

}
public class TextAndFontHelper{
    public static double getTextWidth(Text text){
        double width = text.getBoundsInLocal().getWidth();
        return width;
    }

    public static double getTextHeight(Text text){
        double height = text.getBoundsInLocal().getHeight();
        return height;
    }

    public static double getTextArea(Text text){
        double area = getTextHeight(text)*getTextWidth(text);
        return area;
    }

    public static Font getOptimalFont(String textString, Region textBox,Font font){

        //... This is the method that I want to write

    }
}

These are my attempts:

Attempt #1:This attempt is very glitchy, the text size is continuously changing from a good size(although not perfect as it can be increased a bit) to a big size that doesn't fit the screen every time that the algorithm triggers. https://i.stack.imgur.com/4mGxJ.jpg

        Text text = new Text(textString);
        if (font != null)
            text.setFont(font);

        double textBoxArea = textBox.getHeight()*textBox.getWidth();
        double textArea = getTextArea(text);

        double ratio = textBoxArea/textArea;

        return new Font(text.getFont().getFamily(),text.getFont().getSize()*ratio);

Attempt #2:This attempt is very glitchy, the text size is continuously changing from too small to too big the screen every time that the algorithm triggers. https://i.stack.imgur.com/yOCq2.jpg

        Text text = new Text(textString);
        if (font != null)
            text.setFont(font);

        double heightRatio = textBox.getHeight()/getTextHeight(text);
        double widthRatio = textBox.getWidth()/getTextWidth(text);

        double ratio = heightRatio*widthRatio;
        return new Font(text.getFont().getFamily(),text.getFont().getSize()*ratio);

Attempt #3: This attempt was made based on this question: Resize a SKLabelNode font size to fit?. While this algorithm isn't glitchy, the size of the text is resized to fit just 1 line (sometimes overflowing into the 2nd) and thus being too small. https://i.stack.imgur.com/XkcPq.jpg

        Text text = new Text(textString);
        if (font != null)
            text.setFont(font);

        double heightRatio = textBox.getHeight()/getTextHeight(text);
        double widthRatio = textBox.getWidth()/getTextWidth(text);

        double ratio = Math.min(heightRatio,widthRatio);
        return new Font(text.getFont().getFamily(),text.getFont().getSize()*ratio);
wayne1512
  • 23
  • 1
  • 6
  • Not sure why you want to change the Text Font that said you need to do your test on some condition other than font != null Like where is the textString coming from does each string have variable lengths so if it is a length 12 use font one if it is length 24 use font two If You need further help just comment me back and I will write some code We use the KISS concept of coding so one Font Size fits all – Vector Oct 13 '19 at 03:39
  • @Grendel The reason for changing the font is to change the font size. In fact in my attempts the font family stays the same and only the font size is changed. In case my problem is not clear what I want to create is something similar to this [link](https://imgur.com/a/aRuaR9J) where the font size is changed so the text can be resized automatically. `getOptimalFont(String textString, Region textBox,Font font)` is the method which calculates this font size. – wayne1512 Oct 13 '19 at 08:51
  • @waune1512 I am not 100% sure because I seldom use the TextFlow but in one project as of late I did and discovered that I can not EDIT the text in this container I suggest you test using a TextArea where you have the TextFlow as time permits I will try to run your code So I understand you click a button and the TextFlow resizes and you want to manipulate the text at the same time change font and font size and we are only dealing with two fonts correct ? – Vector Oct 14 '19 at 15:23
  • Have a look at this link and the code in the link This may help with your question https://docs.oracle.com/javase/8/javafx/api/javafx/scene/text/TextFlow.html – Vector Oct 14 '19 at 15:57
  • Look at this SO post it is real clear about what we think the problem is also follow the link to the css style guide https://stackoverflow.com/questions/47562036/javafx-textflow-set-default-text-color – Vector Oct 14 '19 at 16:12
  • @Grendel the font is never changed, only the font size. The part that I am having problems with is caclulating the right font size to resize to. – wayne1512 Oct 14 '19 at 19:12
  • Half the problem is to know the correct search term here is a link that may help https://stackoverflow.com/questions/29926465/nsstring-string-based-on-cgsize How to use sizeWithAttributes might hold the answer to your question – Vector Oct 14 '19 at 20:53
  • Here is a little better LINK https://stackoverflow.com/questions/7259773/how-to-programmatically-resize-an-uibutton-to-the-text-size-and-keep-a-nice-padd/30852376#30852376 – Vector Oct 14 '19 at 20:57

0 Answers0