I have a JavaFX TextFlow
wrapped in a ScrollPane
, and I am trying to get it to automatically scroll to the bottom whenever a new Text
is added to the TextFlow
.
I have tried attaching listeners maxing the ScrollPane
's vvalue
to:
- The
ScrollPane
'svvalue
property itself.- This locks the
ScrollPane
to the bottom, which is not desired.
- This locks the
- The
ScrollPane
'sviewportBounds
property.- This just doesn't work.
- The
TextFlow
's children list.- This scrolls to the location that was the bottom before the latest
Text
was added, strangely. I have tried explicitly requesting layout before scrolling, but this had no effect
- This scrolls to the location that was the bottom before the latest
For an extra big thank you, I'd like to scroll such that if the new addition is too large to display at once, the ScrollPane
scrolls such that the new addition is at the top, and the user should scroll manually to see the 'overflow'. As I said, this would be an added bonus, just scrolling to the bottom would be just fine as I don't expect such large additions (regularly).
And no, I'm not switching to a TextArea
, in which this would be relatively simple. I want to be able to easily add regular, bold and italic text to the TextFlow
, and TextArea
doesn't support this. I also tried Thomas Mikula's RichTextFX, but
- It kept throwing
StackOverflowError
s on internal code without explanation. - I don't really want to use third-party libraries for this project.
So any solution that will work with TextFlow
would be greatly appreciated.
EDIT: Solution, as requested:
private ScrollPane textContainer;
private TextFlow text;
public BaseGui() {
//....
text.getChildren().addListener(
(ListChangeListener<Node>) ((change) -> {
text.layout();
textContainer.layout();
textContainer.setVvalue(1.0f);
}));
textContainer.setContent(text);
//....
}
public void appendBold(String msg) { //similar for italic and regular
append(msg, "-fx-font-weight: bold");
}
private synchronized void append(String msg, String style) {
Platform.runLater(() -> {
Text t = new Text(msg);
t.setFont(segoe(13));
if (!style.equals("")) {
t.setStyle(style);
}
text.getChildren().add(t);
});
}
It won't win any awards for code style, but as this is a personal project I don't really care.