2012-09-07 74 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