JavaFX自动滚动自动更新文本
关于JavaFX的新手问题我一直无法回答,尽管我知道它必须非常简单,而且在我看过的任何地方都找不到任何资源(教程、许多Oracle在线文档、文章、著名的JavaFX博客作者等) 我正在开发一个运行命令行(脚本)的应用程序,我已经成功地从脚本中获得了输出(通过ProcessBuilder),当命令行上发生事情时,我可以以持续的方式显示该脚本。也就是说,我可以做JavaFX自动滚动自动更新文本,javafx,javafx-2,processbuilder,fxml,Javafx,Javafx 2,Processbuilder,Fxml,关于JavaFX的新手问题我一直无法回答,尽管我知道它必须非常简单,而且在我看过的任何地方都找不到任何资源(教程、许多Oracle在线文档、文章、著名的JavaFX博客作者等) 我正在开发一个运行命令行(脚本)的应用程序,我已经成功地从脚本中获得了输出(通过ProcessBuilder),当命令行上发生事情时,我可以以持续的方式显示该脚本。也就是说,我可以做System.out.println(line)一整天,在控制台中显示输出,它只返回正在运行的“myProcess”返回的输入流的输出,创建
System.out.println(line)代码>一整天,在控制台中显示输出,它只返回正在运行的“myProcess”返回的输入流的输出,创建如下:
BufferedReader bri = new BufferedReader(new InputStreamReader(myProcess.getInputStream()))
因此,我能够看到脚本返回的所有输出
我想设置一个JavaFXTextArea或ScrollPane,或者,不确定是什么,以显示这个输出文本(有很多,比如几千行),作为脚本中正在发生的事情的持续“进展”。我有一个场景,我有按钮,从这个场景中获取输入,开始运行脚本,但是现在我想显示点击“运行这个脚本”按钮的结果
我想我需要创建一个或可能是一个有用的开始制作它。不确定
我需要一些关于如何设置绑定或自动滚动/自动更新部分的帮助
有人能为我提供一个开始的地方吗,用JavaFX做这个吗?我宁愿不用秋千
(我使用的是JavaFX2.2、JDK1.7u7,以及所有最新的东西,是的,这是一个FXML应用程序——所以最好是这样做。)
更新:Sergey Grinev的回答在绑定部分非常有用。但这里有一些更详细的说明,当我请求“一些关于如何设置的帮助”时,我的意思是——基本上,我需要将控制权返回到主场景,以允许用户取消脚本,或者监视正在发生的事情。因此,我希望“生成”运行该脚本的进程(也就是说,具有某种“自由运行的进程”),但仍然从中获得输出。(我在最初的问题中对此不是很清楚。)
我在这里使用的技术(见下文)是在进程上执行waitFor,但这当然意味着脚本执行时对话框/场景处于“挂起”状态。我想重新获得控制权,但如何将“p”(进程)传递给其他控制器部件(或者,简单地启动另一个进程,传递参数以启动脚本并让它启动脚本),然后通过Sergey Grinev提到的绑定进行自动更新,而不“挂起”场景/窗口?另外:如果用户请求,我是否可以“停止”另一个进程
以下是我的当前代码(“等待”而脚本——运行需要20-40分钟!——完成;这不是我想要的,我希望将控制权返回给用户):
要记录字符串,可以使用TextArea
要使其异步,您需要为输出读取器创建一个单独的线程
谢谢你,谢尔盖。我对我的问题进行了更新,并补充了一些细节。恐怕我还不完全清楚如何在脚本运行时保持TextArea“更新”,同时将控制权还给用户——理想情况下,用户可以停止脚本——如果他们愿意的话,结束运行脚本的过程。我认为关键是:我需要能够在这两者之间进行通信,通过传递进程id或其他方式,并且能够在必要时“终止”进程。再次感谢。请参阅更新。关于通信和终止,请提出另一个问题。或者搜索网站,这是一个常见的话题。谢谢你,谢尔盖!是的,当我的更新有点长的时候,我考虑问一个单独的问题。。。如果我需要进程间通信/终止的指针,我会这样做(当然,先在这里和其他地方搜索一下)。再次感谢!一旦我成功了,我会接受你的答案——我已经投了赞成票。干杯。除了stop()代码>在我的FXML应用程序中。我一直在谷歌上搜索,似乎不知道如何在控制器类和应用程序类之间进行交互。显然,有很多方法没有使用FXML,但是很少(我找不到)用FXML讨论它,尽管我认为原理应该是相似的。这是我的新问题:同时再次感谢你的帮助。我接受了你的回答。
public class MyController implements Initializable {
@FXML
private void handleRunScript(ActionEvent event) throws IOException {
ProcessBuilder pb = new ProcessBuilder("myscript.sh", "arg1", "arg2", ...);
Process p = pb.start();
try {
BufferedReader bri = new BufferedReader
(new InputStreamReader(p.getInputStream()));
String line;
while ((line = bri.readLine()) != null) {
System.out.println(line);
textAreaRight.setText(line);
}
bri.close();
p.waitFor();
}
catch (Exception err) {
err.printStackTrace();
}
}
@FXML
private void handleCancel(ActionEvent event) {
doSomethingDifferent();
}
}
public class DoTextAreaLog extends Application {
TextArea log = new TextArea();
Process p;
@Override
public void start(Stage stage) {
try {
ProcessBuilder pb = new ProcessBuilder("ping", "stackoverflow.com", "-n", "100");
p = pb.start();
// this thread will read from process without blocking an application
new Thread(new Runnable() {
@Override
public void run() {
try {
//try-with-resources from jdk7, change it back if you use older jdk
try (BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line;
while ((line = bri.readLine()) != null) {
log(line);
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}).start();
stage.setScene(new Scene(new Group(log), 400, 300));
stage.show();
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public void stop() throws Exception {
super.stop();
// this called on fx app close, you may call it in user action handler
if (p!=null ) {
p.destroy();
}
}
private void log(final String st) {
// we can access fx objects only from fx thread
// so we need to wrap log access into Platform#runLater
Platform.runLater(new Runnable() {
@Override
public void run() {
log.setText(st + "\n" + log.getText());
}
});
}
public static void main(String[] args) {
launch();
}
}