JavaFX TextArea和autoscroll

Sam*_*ays 17 java javafx-2

我试图让TextArea自动滚动到底部,新文本通过事件处理程序放入.每个新条目只是一个长字符串,每个条目用换行符分隔.我尝试过一个更改处理程序,它将setscrolltop设置为Double.MIN_VALUE,但无济于事.有关如何做到这一点的任何想法?

Mat*_*ath 25

您必须向TextArea元素添加一个侦听器,以便在其值更改时滚动到底部:

@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
    }
});
Run Code Online (Sandbox Code Playgroud)

但是当你使用这个setText(text)方法时不会触发这个监听器,所以如果你想在setText(text)使用它之后触发appendText(text)它:

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
Run Code Online (Sandbox Code Playgroud)

这听起来更像是一个bug,一旦它setText()应该触发changed听众,但事实并非如此.这是我自己使用的解决方法,希望它对您有所帮助.

  • 我似乎无法让它工作,我的TextArea只是保持滚动到顶部.有任何想法吗?两者都使用`Platform.runLater(() - > this.setScrollTop(Double.MAX_VALUE));`或`setScrollTop(Double.MAX_VALUE)`.另外我的Textarea似乎很模糊. (3认同)
  • `setScrollTop(Double.MIN_VALUE);`滚动到顶部,而`MAX_VALUE`滚动到底部. (2认同)
  • 我建议在Platform.runLater()中设置滚动 - 我的文本区域有时会错过一些没有它的滚动更新. (2认同)

jam*_*own 11

txa.appendText("")将在没有监听器的情况下滚动到底部.如果要向后滚动并且文本不断更新,这将成为一个问题.txa.setText("")将滚动条放回顶部,同样的问题也适用.

我的解决方案是扩展TextArea类,将textArea的FXML标记修改为LogTextArea.如果这样做,它显然会导致场景构建器出现问题,因为它不知道这个组件是什么

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;
}

}
Run Code Online (Sandbox Code Playgroud)


Ano*_*lus 6

无需使用appendText即可替代该奇怪的setText错误的方法

textArea.selectPositionCaret(textArea.getLength());
textArea.deselect(); //removes the highlighting
Run Code Online (Sandbox Code Playgroud)


小智 5

我没有足够的声誉来发表评论,但想为以后的读者提供一些见解,以了解为何setText似乎没有触发监听器,而appendText却如此,就像Math的回答一样。

我自己遇到类似问题时就找到了这个答案,并调查了代码。目前,这是Google搜索中“ javafx textarea settext scroll”的最高搜索结果。

setText确实会触发侦听器。根据TextInputControl(TextArea的超类)的doSet方法的javadoc:

     * doSet is called whenever the setText() method was called directly
     * on the TextInputControl, or when the text property was bound,
     * unbound, or reacted to a binding invalidation. It is *not* called
     * when modifications to the content happened indirectly, such as
     * through the replaceText / replaceSelection methods.
Run Code Online (Sandbox Code Playgroud)

在doSet方法内,对updateText()进行了调用,TextArea覆盖了该方法:

  @Override final void textUpdated() {
        setScrollTop(0);
        setScrollLeft(0);
    }  
Run Code Online (Sandbox Code Playgroud)

因此,当您按照Math的答案在侦听器中设置滚动量时,会发生以下情况:

  1. TextProperty已更新
  2. 将调用您的听众,并设置了滚动条
  3. doSet被称为
  4. textUpdated被称为
  5. 滚动设置回到左上角

当您附加“”时,

  1. TextProperty已更新
  2. 将调用您的听众,并设置了滚动条

上面的javadoc很清楚为什么是这种情况-仅在使用setText时才调用doSet。实际上,appendText调用insertText,后者调用replaceText-并且javadoc进一步声明replaceText不会触发对doSet的调用。

这种行为非常令人讨厌,特别是因为这些都是最终方法,乍一看并不明显-但这不是错误。