2016-09-14 11 views
0

問題は単純ですが、それは私を狂ってしまっています。JavaFX TextArea appendTextは初期化では動作しますが、他の場所では動作しません。

私は TextArea、と定義している私のプログラムで

:テキストを表示するために取得する方法上の任意のアイデアは素晴らしいことだ

<TextArea fx:id="output" editable="false" prefHeight="300.0" prefWidth="200.0" text="Output" GridPane.columnSpan="2" GridPane.rowIndex="4" /> 
@FXML private TextArea output; 

... 

public void initialize(URL url, ResourceBundle rb) { 
    output.setText("Test"); //Test appears correctly in output 
    ... 
} 

@FXML 
public void download() { 
    String outputTemplate = templateField.getText(); 
    String url = urlField.getText(); 
    System.out.println("Downloading from " + url); 
    try { 
     Process down = Runtime.getRuntime().exec("youtube-dl -o \"" + outputTemplate + "\" " + url); 
     BufferedReader reader = new BufferedReader(new InputStreamReader(down.getInputStream())); 
     String line; 
     while ((line = reader.readLine()) != null) { 
      System.out.println(line); //Prints as expected 
      output.appendText(line + "\n"); //Has no effect 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

、私は別のプログラムに前にこれをやりましたちょうど何らかの理由で、今度はカンタンです。

EDIT:実際には、が終了してループを終了した後に結果を出力します。

答えて

3

UIに表示されるテキストは、レイアウトパルスによって変化します。レイアウトパルスは、JavaFXアプリケーションスレッドで実行されます。 downloadメソッドのようなイベントハンドラは、同じスレッド上で実行されるため、完了するまでレイアウトや処理などのイベントが発生することはありません。このため、長いスレッドでこのスレッドをブロックするのではなく、別のスレッドでスレッドを実行する必要があります。

UIへの更新は、テキストを追加するPlatform.runLaterを使用して、アプリケーションスレッドから実行する必要がありますので:

@FXML 
public void download() { 
    String outputTemplate = templateField.getText(); 
    String url = urlField.getText(); 
    Runnable r =() -> { 
     System.out.println("Downloading from " + url); 
     try { 
      Process down = Runtime.getRuntime().exec("youtube-dl -o \"" + outputTemplate + "\" " + url); 
      BufferedReader reader = new BufferedReader(new InputStreamReader(down.getInputStream())); 
      String line; 
      while ((line = reader.readLine()) != null) { 
       System.out.println(line); //Prints as expected 
       final String printText = line + "\n"; 

       // append the line on the application thread 
       Platform.runLater(() -> output.appendText(printText)); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    }; 
    // run task on different thread 
    Thread t = new Thread(r); 
    t.start(); 
} 
0

問題は、メインスレッドでこれを実行していることです。したがって、サイクルが終了するまでステージを更新することはできません。新しいスレッドで試してください:

@FXML 
public void download() { 
    Task<Void> task = new Task<Void>() { 
     @Override 
     protected Void call() { 
      String outputTemplate = templateField.getText(); 
      String url = urlField.getText(); 
      System.out.println("Downloading from " + url); 
      try { 
       Process down = Runtime.getRuntime().exec("youtube-dl -o \"" + outputTemplate + "\" " + url); 
       BufferedReader reader = new BufferedReader(new InputStreamReader(down.getInputStream())); 
       String line; 
       while ((line = reader.readLine()) != null) { 
        System.out.println(line); // Prints as expected 
        output.appendText(line + "\n"); // Has no effect 
       } 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      return null; 
     } 
    }; 
    new Thread(task).start(); 
} 
+0

あなたは 'バックグラウンドスレッドからoutput'を変更することはできません。 –

+0

どうしてですか?できます。それともスレッドセーフではないということですか? – gearquicker

+0

スレッドセーフではありません。 [Javadocs](http://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html)から、「JavaFXアプリケーション・スレッドでライブ・オブジェクトの変更を行う必要があります。したがって、特定のプラットフォームで動作する可能性がありますが、一般的には動作する保証はありません。 –

関連する問題