We are trying to count the number of rows in a TextArea
Here are the TextArea properties PrefWidth 600 and PrefHeight 620 with MaxHeight 620
Wrap Text is set to true. We
As already noted by @Slaw in one of his comments, there is no public API to access the line count in a textArea (emphasis by me). On the other hand, there is internal API that provides what we need - if we are daring enough and allowed to work with internals.
Looking at public api and digging into the implementation details of TextAreaSkin, it turns out that (currently, up to fx13 and probably later)
textArea.getParagraphs()
seems to return the charSequences that are separated by a hard linebreakgetLines()
which returns an array of textLines separated by either soft or hard linebreaks, for counting we are only interested in its length.Below is a quick example that demonstrates how to make use of these internals. Basically, it looks up the area's text node (available after the skin is attached), reflectively accesses its textLayout and query the length of the lines array.
Note that this is for fx9+ (probabbly not much changed against fx8 except for pulling the skins into public scope, didn't check, though). To allow access to internals, we need to tweak module access restrictions at both compiletime and runtime.
Compiletime:
--add-exports javafx.graphics/com.sun.javafx.scene.text=ALL_UNNAMED
Runtime:
--add-opens javafx.graphics/com.sun.javafx.scene.text=ALL-UNNAMED
--add-opens javafx.graphics/javafx.scene.text=ALL-UNNAMED
The example to play with:
public class TextAreaLineCount extends Application {
String info = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
"Nam tortor felis, pulvinar in scelerisque cursus, pulvinar at ante. " +
"Nulla consequat congue lectus in sodales.";
private Parent createContent() {
TextArea area = new TextArea(info);
area.setWrapText(true);
area.appendText("\n" + info);
Button append = new Button("append paragraph");
append.setOnAction(e -> {
area.appendText("\n " + info);
LOG.info("paragraphs: " + area.getParagraphs().size());
});
Button logLines = new Button("log lines");
logLines.setOnAction(e -> {
Text text = (Text) area.lookup(".text");
// getTextLayout is a private method in text, have to access reflectively
// this is my utility method, use your own :)
TextLayout layout = (TextLayout) FXUtils.invokeGetMethodValue(Text.class, text, "getTextLayout");
LOG.info("" + layout.getLines().length);
});
BorderPane content = new BorderPane(area);
content.setBottom(new HBox(10, append, logLines));
return content;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(TextAreaLineCount.class.getName());
}