我试图让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听众,但事实并非如此.这是我自己使用的解决方法,希望它对您有所帮助.
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)
无需使用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:
Run Code Online (Sandbox Code Playgroud)* 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.
在doSet方法内,对updateText()进行了调用,TextArea覆盖了该方法:
@Override final void textUpdated() {
setScrollTop(0);
setScrollLeft(0);
}
Run Code Online (Sandbox Code Playgroud)
因此,当您按照Math的答案在侦听器中设置滚动量时,会发生以下情况:
当您附加“”时,
上面的javadoc很清楚为什么是这种情况-仅在使用setText时才调用doSet。实际上,appendText调用insertText,后者调用replaceText-并且javadoc进一步声明replaceText不会触发对doSet的调用。
这种行为非常令人讨厌,特别是因为这些都是最终方法,乍一看并不明显-但这不是错误。