JavaFX自动滚动自动更新文本

JavaFX自动滚动自动更新文本,javafx,javafx-2,processbuilder,fxml,Javafx,Javafx 2,Processbuilder,Fxml,关于JavaFX的新手问题我一直无法回答,尽管我知道它必须非常简单,而且在我看过的任何地方都找不到任何资源(教程、许多Oracle在线文档、文章、著名的JavaFX博客作者等) 我正在开发一个运行命令行(脚本)的应用程序,我已经成功地从脚本中获得了输出(通过ProcessBuilder),当命令行上发生事情时,我可以以持续的方式显示该脚本。也就是说,我可以做System.out.println(line)一整天,在控制台中显示输出,它只返回正在运行的“myProcess”返回的输入流的输出,创建

关于JavaFX的新手问题我一直无法回答,尽管我知道它必须非常简单,而且在我看过的任何地方都找不到任何资源(教程、许多Oracle在线文档、文章、著名的JavaFX博客作者等)

我正在开发一个运行命令行(脚本)的应用程序,我已经成功地从脚本中获得了输出(通过ProcessBuilder),当命令行上发生事情时,我可以以持续的方式显示该脚本。也就是说,我可以做
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();
        }
    }