如果溢出,请调整 JavaFX 标签的大小



我在 TitledPane 的 GridPane 中有一个标签。如果它被溢出,我希望它逐步缩小 0.05em,这样三个点("Long Labe...")就不会显示 ->"长标签"小。

标签的isOverrun()方法会很棒,但JavaFX不提供,生活也不是一个愿望。
所以我到目前为止的工作:

    Bounds tpBounds = tPane.getBoundsInLocal();
    Bounds lblBounds = label.getBoundsInLocal();
    Double fontSize = 1.0;
    while (tpBounds.getWidth() < lblBounds.getWidth() && fontSize > 0.5) {
        fontSize = fontSize-0.05;
        label.setStyle("-fx-font-size: "+fontSize+"em;");
        System.out.println(fontSize+" "+tpBounds.getWidth()+" "+lblBounds.getWidth());
    }

问题:在while循环期间,bounds.getWidth()总是显示原始宽度。新字体大小的"新"宽度刷新速度不够快,无法被 while 条件捕获,因此字体大小越来越低。
有什么解决方案吗?编辑我更常问:让标签自己缩小尺寸真的那么难吗,直到它适合而不截断?!


另一种工作方式是:

.setMinHeight(Region.USE_PREF_SIZE)

简单,比计算容易得多。

这是一个受内部 API 启发的黑客。

JavaFX使用com.sun.javafx.scene.control.skin.Utils类进行各种基于文本的计算。这还包括计算溢出文本,以剪切原始文本的程度以及显示省略号文本的位置等。

对于未换行和非多行标签文本,此类中仅使用 3 种方法:

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) {...}

由于这个类是一个内部 api,我只是将这 3 个方法(以及必要的类变量)复制到我自己的 Utils 类中,并用作:

@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();
}

根据您的要求,您可以简化逻辑并进一步缩短computeClippedText()方法的计算时间。

解决方案:

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

此解决方法不是 100% 令人满意的,由于 label.setStyle("...") 上的图形更新速度缓慢,GUI 正在受到影响;
在 styleProperty-listener 启动之前需要几毫秒。
我试图解决这个问题几个星期,总是找到一个可能的解决方案,但它没有奏效。我希望有人从这篇文章中获利。

这个函数做魔术,基本上计算当前标签宽度的计算大小 preferedWidth(可以根据标签的设置而改变),如果它更大,则减少 0.5 字体(也可以是可选的自定义值)。

注意:请考虑还将条件设置为字体小于 0.5 以避免字体未达到 0。也可以使用 while 而不是递归函数进行转换,并且也是最佳的,我会同时设置两者以防万一

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

相关内容

  • 没有找到相关文章

最新更新