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