2012-09-07 49 views
4

关于JavaFX的新手问题,我一直无法回答,尽管知道它必须非常简单,并且在我看过的任何地方找不到任何资源(教程,很多Oracle在线文档,文章,着名的JavaFX博客等)JavaFX自动滚动自动更新文本

我正在开发一个运行应用程序的命令行(脚本),并且我已经成功地从脚本中获得输出(通过ProcessBuilder)以正在进行的方式显示,就像事情发生在命令行上一样。也就是说,我可以做System.out.println(line);整天,显示在控制台,它只是返回由“myProcess”那是运行返回输入流输出的输出,这样创建:

BufferedReader bri = new BufferedReader(new InputStreamReader(myProcess.getInputStream())) 

所以我能够查看从脚本返回的所有输出。

我想建立一个JavaFX的TextArea或ScrollPane中,或者不知道,可显示该输出文本(有很多的它,像几千行)作为一个什么样的发生正在进行的“进步”在脚本中,正如它发生的那样。我有一个场景,我有按钮,并从这个场景获得输入来启动脚本运行,但现在我想显示点击按钮“RUN THIS SCRIPT”的结果,可以这么说。

我假设我需要创建一个TextArea as described here,或者TextBuilder将开始制作它。不确定。

我需要一些帮助,以了解如何设置绑定或自动滚动/自动更新部分。

有人可以为我提供一个开始的地方,用JavaFX做到这一点吗?我宁愿不使用Swing。

(我使用JavaFX 2.2,JDK 1.7u7,所有最新的东西,是的,这是一个FXML应用程序 - 这样做这样的说法将是首选。)

UPDATE:谢尔盖Grinev的答案在绑定部分非常有帮助。但是,当我要求“在如何设置时提供一些帮助”时,这里有一些更详细的信息 - 基本上,我需要将控制返回到主场景以允许用户取消脚本或以其他方式监视这是怎么回事。所以我想“产生”运行该脚本的流程(即,有一些“自由运行流程”),但仍然从中获得输出。 (我在最初的问题上并不十分清楚)

我在这里使用的技术(见下文)是在进程上执行waitFor,但当然这意味着dialog/Scene是'挂起'脚本执行。我想获得控制权,但是如何将'p'(Process)传递给其他控制器块(或者,也可以简单地启动另一个传入参数的进程以启动脚本并启动脚本),然后将通过绑定Sergey Grinev提到的自动更新 - 没有“悬挂”场景/窗口?另外:如果用户请求,我可以'停止'这个其他进程吗?

这是我当前的代码('等待'脚本 - 需要20-40分钟才能运行! - 完成;这是而不是我想要的,我想控制返回给用户):

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

回答

5
  1. 要登录的字符串,您可以使用文本区域
  2. 为了让asynchronious你需要为输出读者一个单独的线程。

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(); 
    } 
} 
+0

感谢谢尔盖。我为我的问题添加了更新,并提供了一些更具体的内容。恐怕我并没有完全清楚如何在脚本运行时保持TextArea“更新”,同时还将控制权交还给用户 - 理想情况下,用户能够停止脚本 - 结束正在运行它的进程 - 如果他们想要的话。我认为关键是:我需要能够在这两者之间进行沟通,通过传递进程ID或其他东西,并在必要时能够“杀死”进程。再次感谢。 – likethesky

+0

请参阅更新。为了沟通和终止,请提出另一个问题。或者搜索网站,这是一个常见的话题。 –

+0

美丽。感谢Sergey!是的,当我的更新有点长时,我考虑询问一个单独的问题......如果我需要进程间通信/终止指针(当然在这里和其他地方搜索一下之后),我会这样做。再次感谢!一旦我得到它的工作,我会接受你的答案 - 它已经得到我的赞扬。干杯。 – likethesky