Is it possible to truncate a Label or a Text after a fixed number of lines in JavaFX? For the Web there is a CSS property called 'line-clamp'. Unfortunately there doesn't seem to be an equivalent in JavaFX.
With a Label you can either choose to wrap the text or truncate it with ellipsis shown. With the Text object it is at least possible to specify the wrapping with.
Not wrapped and not truncated:
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eir mod tempor invidunt ut labore et dolore magna aliquyam
Wrapped and not truncated:
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore
magna aliquyam
Not wrapped and truncated:
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, ...
Wrapped and truncated after 2 lines (desired behavior):
Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore ...
I've came up with fairly basic solution (that can be further improved).
public class MultiLineLabel extends VBox {
private final String text;
private final List<Label> lines = new ArrayList<>();
public MultiLineLabel(String text, int maxNumberOfLines) {
if (maxNumberOfLines < 1) {
throw new IllegalArgumentException();
}
this.text = text;
// Create num. of lines labels
for (int i=0; i<maxNumberOfLines; i++) {
final Label label = new Label();
lines.add(label);
label.setTextOverrun(OverrunStyle.CLIP);
}
getChildren().addAll(lines);
}
@Override
protected void layoutChildren() {
super.layoutChildren();
String remainingText = this.text;
for (Iterator<Label> iterator = lines.iterator(); iterator.hasNext(); ) {
final Label currentLine = iterator.next();
// If this is the last line, just set the text and finish
if (!iterator.hasNext()) {
currentLine.setText(remainingText);
currentLine.setTextOverrun(OverrunStyle.ELLIPSIS);
break;
} else {
final String textThatFitsInThisLine = Utils.computeClippedText(currentLine.getFont(), remainingText, this.getWidth(), OverrunStyle.CLIP, null);
currentLine.setText(textThatFitsInThisLine);
remainingText = remainingText.substring(textThatFitsInThisLine.length());
}
}
}
}
... that can then be used like:
public class MultiLineLabelSSCCE extends Application {
@Override
public void start(Stage stage) {
final MultiLineLabel multiLineLabel =
new MultiLineLabel("This is some interesting text. The question is whether it's truncated properly. Let's see.", 3);
stage.setScene(new Scene(multiLineLabel));
stage.show();
}
}
Demo (of the above solution):
I hope this suffices for what you need it for.
Side note:
This solutions is based on com.sun.javafx.scene.control.skin.Utils
which is considered an implementation detail and is not part of JavaFx API. To run the code using this solution you might need to add:
--add-exports=javafx.controls/com.sun.javafx.scene.control.skin=org.example
to your run configuration (VM options)