Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX TextArea and autoscroll

Tags:

java

javafx-2

I am trying to get a TextArea to autoscroll to the bottom with new text which is put in via an event handler. Each new entry is just one long string of text with each entry separated by a line break. I have tried a change handler which sets setscrolltop to Double.MIN_VALUE but to no avail. Any ideas of how this could be done?

like image 476
Sam Keays Avatar asked Jul 22 '13 23:07

Sam Keays


2 Answers

You have to add a listener to the TextArea element to scroll to the bottom when it's value is changed:

@FXML private TextArea txa; 

...

txa.textProperty().addListener(new ChangeListener<Object>() {
    @Override
    public void changed(ObservableValue<?> observable, Object oldValue,
            Object newValue) {
        txa.setScrollTop(Double.MAX_VALUE); //this will scroll to the bottom
        //use Double.MIN_VALUE to scroll to the top
    }
});

But this listener is not triggered when you use the setText(text) method, so if you want to trigger it after a setText(text) use the appendText(text) right after it:

txa.setText("Text into the textArea"); //does not trigger the listener
txa.appendText("");  //this will trigger the listener and will scroll the
                     //TextArea to the bottom

This sounds more like a bug, once the setText() should trigger the changed listener, however it doesn't. This is the workaround I use myself and hope it helps you.

like image 86
Math Avatar answered Oct 17 '22 14:10

Math


txa.appendText("") will scroll to the bottom without a listener. This becomes an issue if you want to scroll back and the text is being constantly updated. txa.setText("") puts the scroll bar back at the top and same issue applies.

My solution was to extend the TextArea class, ammend the FXML tag from textArea to LogTextArea. Where this works, it clearly causes problems in scene builder as it does not know what this component is

import javafx.scene.control.TextArea;
import javafx.scene.text.Font;

public class LogTextArea extends TextArea {

private boolean pausedScroll = false;
private double scrollPosition = 0;

public LogTextArea() {
    super();
}

public void setMessage(String data) {
    if (pausedScroll) {
        scrollPosition = this.getScrollTop();
        this.setText(data);
        this.setScrollTop(scrollPosition);
    } else {
        this.setText(data);
        this.setScrollTop(Double.MAX_VALUE);
    }
}

public void pauseScroll(Boolean pause) {
    pausedScroll = pause;
}

}
like image 40
jamesarbrown Avatar answered Oct 17 '22 16:10

jamesarbrown