使用自动滚动将处理输出流式传输到 Java FX 文本区域
Stream Process Output to Java FX Text Area with Auto Scroll
我正在构建和创建一个进程的应用程序,并将其标准输出流式传输到 javafx 文本区域。就像终端模拟器一样,如果进程显示太多行,我希望输出自动滚动到控制台的末尾。
问题是文本区域不会滚动到文本末尾,而是停留在顶部。另一个奇怪的行为是当我尝试使用鼠标滚轮/键盘/滚动条滚动文本区域时,文本区域滚动到最顶部。
我已经试过答案 here, here, and 。看来我哪里有问题
这是方法 void streamToTextArea(java.lang.Process process)
的内容 - 在执行进程并将其流式传输到 consoleTextArea
时执行繁重工作的方法。
Task bgTask = new Task<Void>() {
@Override
protected void call() throws Exception {
InputStream inputStream = process.getInputStream();
StringBuilder consoleContent = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while((line = reader.readLine()) != null) {
consoleContent
.append(line)
.append("\n");
updateMessage(consoleContent.toString());
consoleTextArea.appendText(""); // trigger ChangeListener
}
} catch (IOException e) { doSomething(e); }
return null;
}
};
StringProperty textProperty = consoleTextArea.textProperty();
textProperty.addListener((observable, oldValue, newValue) -> {
// currently:
consoleTextArea.selectPositionCaret(consoleTextArea.getLength());
consoleTextArea.deselect();
// also tried:
// consoleTextArea.setScrollTop(Double.MAX);
});
textProperty.bind(bgTask.messageProperty());
// start bgTask as daemon thread
// add event handling when bgTask ended
首先Task.call()
方法不是在JavaFX应用程序线程中执行的,所以在这个方法中改变当前视图的任何状态都是不合适的。您在错误的线程中将 ""
添加到 consoleTextArea
。你应该这样做:
Platform.runLater(() -> {
consoleTextArea.appendText("");
});
第二个问题是调用consoleTextArea.appendText("");
不会触发你的ChangeListener
(事实上,它什么也不会做),因为你将consoleTextArea文本属性绑定到Task
消息 属性 textProperty.bind(bgTask.messageProperty());
。在那种情况下,文本区域将只监听 Task
消息 属性 中的文本变化。将您的侦听器添加到消息 属性:
bgTask.messageProperty().addListener((observable, oldValue, newValue) -> {
// currently:
consoleTextArea.selectPositionCaret(consoleTextArea.getLength());
consoleTextArea.deselect();
// also tried:
// consoleTextArea.setScrollTop(Double.MAX);
});
我正在构建和创建一个进程的应用程序,并将其标准输出流式传输到 javafx 文本区域。就像终端模拟器一样,如果进程显示太多行,我希望输出自动滚动到控制台的末尾。
问题是文本区域不会滚动到文本末尾,而是停留在顶部。另一个奇怪的行为是当我尝试使用鼠标滚轮/键盘/滚动条滚动文本区域时,文本区域滚动到最顶部。
我已经试过答案 here, here, and
这是方法 void streamToTextArea(java.lang.Process process)
的内容 - 在执行进程并将其流式传输到 consoleTextArea
时执行繁重工作的方法。
Task bgTask = new Task<Void>() {
@Override
protected void call() throws Exception {
InputStream inputStream = process.getInputStream();
StringBuilder consoleContent = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while((line = reader.readLine()) != null) {
consoleContent
.append(line)
.append("\n");
updateMessage(consoleContent.toString());
consoleTextArea.appendText(""); // trigger ChangeListener
}
} catch (IOException e) { doSomething(e); }
return null;
}
};
StringProperty textProperty = consoleTextArea.textProperty();
textProperty.addListener((observable, oldValue, newValue) -> {
// currently:
consoleTextArea.selectPositionCaret(consoleTextArea.getLength());
consoleTextArea.deselect();
// also tried:
// consoleTextArea.setScrollTop(Double.MAX);
});
textProperty.bind(bgTask.messageProperty());
// start bgTask as daemon thread
// add event handling when bgTask ended
首先Task.call()
方法不是在JavaFX应用程序线程中执行的,所以在这个方法中改变当前视图的任何状态都是不合适的。您在错误的线程中将 ""
添加到 consoleTextArea
。你应该这样做:
Platform.runLater(() -> {
consoleTextArea.appendText("");
});
第二个问题是调用consoleTextArea.appendText("");
不会触发你的ChangeListener
(事实上,它什么也不会做),因为你将consoleTextArea文本属性绑定到Task
消息 属性 textProperty.bind(bgTask.messageProperty());
。在那种情况下,文本区域将只监听 Task
消息 属性 中的文本变化。将您的侦听器添加到消息 属性:
bgTask.messageProperty().addListener((observable, oldValue, newValue) -> {
// currently:
consoleTextArea.selectPositionCaret(consoleTextArea.getLength());
consoleTextArea.deselect();
// also tried:
// consoleTextArea.setScrollTop(Double.MAX);
});