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