JavaFX TextArea appendText 在初始化中有效,但在其他地方无效

JavaFX TextArea appendText works in initialize but not elsewhere

问题很简单,但它让我抓狂。

在我的程序中我有一个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();
    }
}

任何关于如何让文本出现的想法都很好,我以前在不同的程序上这样做过,只是出于某种原因,这次它很坏

编辑:经过进一步修改,它实际上会打印出结果,但只有在 Process 结束并退出循环之后。

问题是您是在主线程中执行此操作。所以阶段不能更新,直到循环结束。在新线程中尝试:

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

UI 中显示的文本随布局脉冲而变化。布局脉冲在 JavaFX 应用程序线程上完成。事件处理程序,例如同一线程上的 download 方法 运行 有效地阻止它在完成之前进行任何布局或处理以及其他事件。这就是为什么你不应该用 long运行ning 任务阻塞这个线程,而是在不同的线程上执行它们。

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