Resize JavaFX Label if overrun

混江龙づ霸主 提交于 2019-11-28 12:58:13

This is a hack inspired from internal api.

The JavaFX uses com.sun.javafx.scene.control.skin.Utils class to various text based calculations. This also includes calculation of overrun texts to how much clip the original text and at where to show ellipsis text etc.

For the not wrapped and not multiline label texts there is only 3 methods used in this class:

static String computeClippedText(Font font, String text, double width, OverrunStyle type, String ellipsisString)
static double computeTextWidth(Font font, String text, double wrappingWidth) {...}
static int computeTruncationIndex(Font font, String text, double width) {...}

Since this class is an internal api, I just copied those 3 methods (along with necessary class variables) to my own Utils class and used as:

@Override
public void start( Stage primaryStage )
{
    final Label label = new Label( "Lorem Ipsum is simply dummy long text of the printing and typesetting industry" );
    label.setFont( Font.font( 10 ) );
    System.out.println( "originalText = " + label.getText() );

    Platform.runLater( () -> 
        {
            Double fontSize = label.getFont().getSize();
            String clippedText = Utils.computeClippedText( label.getFont(), label.getText(), label.getWidth(), label.getTextOverrun(), label.getEllipsisString() );
            Font newFont = label.getFont();

            while ( !label.getText().equals( clippedText ) && fontSize > 0.5 )
            {
                System.out.println( "fontSize = " + fontSize + ", clippedText = " + clippedText );
                fontSize = fontSize - 0.05;
                newFont = Font.font( label.getFont().getFamily(), fontSize );
                clippedText = Utils.computeClippedText( newFont, label.getText(), label.getWidth(), label.getTextOverrun(), label.getEllipsisString() );
            }

            label.setFont( newFont );
    } );

    Scene scene = new Scene( new VBox(label), 350, 200 );
    primaryStage.setScene( scene );
    primaryStage.show();
}

Based on your requirements you can simplify the logic and improve the calculation time of computeClippedText() method further.

Solution:

fontVerkleinerung(lblXYZ);   //call resizing at beginning


 lblXYZ.styleProperty().addListener((observable, oldV, newV) -> {
    fontVerkleinerung(lblXYZ);   //check size again if resized
 }); 


private void fontVerkleinerung(Label label) {
    Platform.runLater(() -> {
        tpBounds = tPane.getBoundsInLocal();
        if (label.getBoundsInLocal().getWidth()>tpBounds.getWidth() && !fontSizeFits) {
            fontSize = fontSize-0.02;
            label.setStyle("-fx-font-size: "+fontSize+"em;");
        }

        if (label.getBoundsInLocal().getWidth()<=tpBounds.getWidth() && !fontSizeFits) {
            fontSizeFits = true;
        }
    });
}

This workaround is not 100% satisfying, the GUI is suffering due to the slow graphic updaterate on label.setStyle("...");
It takes a few ms till the styleProperty-listener kicks in.
I tried to fix this for a few weeks now, always found a probably-solution but it didn't work. I hope somebody profits from this post.

One other way which is working is:

.setMinHeight(Region.USE_PREF_SIZE)

Simple and much easier than calculate it.

this function does the magic, basically calculates the compute size of the current label width the preferedWidth(could be change depending of the setting of the label) and if its bigger then reduce by 0.5 the font (also optional could be a custom value).

note: considere also set a condition to if the font is less than 0.5 to avoid that the font to not reach 0. Also could be converted with while instead of recursive function and also will be optimal, I will set both just in case

public Label ResizeTextIfOverrunRecursive(Label label, String text, double size) throws Exception {
    FontLoader fontLoader = Toolkit.getToolkit().getFontLoader();
    label.setFont(Font.font(size));
    double font = label.getFont().getSize();
    label.setStyle("-fx-font-size:" + (font) +"px;");
    label.applyCss();
    label.layout();
    label.setText(text);
    double prefWidth = label.getPrefWidth();
    if (fontLoader.computeStringWidth(label.getText(), label.getFont()) > prefWidth){
        return ResizeTextIfOverrunRecursive(label, text, size - 0.5);
    } else return label;
}

public void ResizeTextIfOverrunItaration(Label label, String text, double size) throws Exception {
    FontLoader fontLoader = Toolkit.getToolkit().getFontLoader();
    label.setFont(Font.font(size));
    double font = label.getFont().getSize();
    label.setStyle("-fx-font-size:" + (font) +"px;");
    label.applyCss();
    label.layout();
    double prefWidth = label.getPrefWidth();
    while (fontLoader.computeStringWidth(label.getText(), label.getFont()) > prefWidth){
        font -= 0.5;
        label.setStyle("-fx-font-size:" + (font) +"px;");
        label.applyCss();
        label.layout();
    }

    label.setText(text);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!