Java FX:无法从不同的FX线程

时间:2016-06-13 14:10:54

标签: java multithreading javafx concurrency

您好我有应用程序,它在GUI(Java FX)和命令行上运行。 以GUI身份运行时,我会在文本区域显示状态。这很好。

但问题是,当我尝试从某些不同的(非javafx)类显示错误(通过弹出窗口)时,它向我显示Java Fx - 线程异常不在FX线程上。

以下是我的代码

这是我想要显示弹出窗口的Java FX类。

public class DeploymentProcesController implements Initializable {


@FXML
private TextArea statusTextArea;

@Override
public void initialize(URL location, ResourceBundle resources) {

}

public void updateGUIMessage(String message) {
    if (Platform.isFxApplicationThread()) {
        statusTextArea.appendText(message);
    } else {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                statusTextArea.appendText(message);
            }
        });
    }
}

public void displayAlertMessages(final String message) {
    Platform.setImplicitExit(false);
    Task<Void> task = new Task<Void>() {
        @Override public Void call() {
            Platform.runLater(new Runnable() {
                public void run() {
                    Alert alert = new Alert(AlertType.INFORMATION, message, ButtonType.OK);
                    alert.showAndWait();
                }
            });

            return null;
        }
    };
    new Thread(task).start();
}

}

我有一个非FX类,这是切入点。所以根据运行类型(命令行/ GUI)我更新状态。

以下是我打电话来更新状态的信息。

public void promptUser(String message,boolean isCommandLineRun){
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    if(isCommandLineRun) {
        System.out.println(simpleDateFormat.format(new Date()) + " - " + message);
    } else {
        controller.displayAlertMessages(message);
    }
}

当我从非fx类调用updateGUIMessage方法时,我没有任何问题。这是因为statusArea元素在FX线程(此fx类的成员)上。

此外,在单击某个按钮时生成警告框也没有问题, 但要显示来自不同类的警告框 - 我遇到问题,因为一旦我尝试生成警报框,应用程序崩溃,说不在fx线程上。

我知道“警报”框是一个弹出窗口,因此可能未处理。但是,任何人都可以帮助我,我想向用户展示来自不同班级的警报框。

3 个答案:

答案 0 :(得分:1)

UI中的所有内容都必须从UI应用程序线程执行。这正是错误信息的含义。

幸运的是,您可以简单地将您的调用包装起来,以便在UI线程中执行:

if(isCommandLineRun) {
    System.out.println(simpleDateFormat.format(new Date()) + " - " + message);
} else {
    Platform.runLater(() -> controller.displayAlertMessages(message));
}

答案 1 :(得分:0)

终于找到了解决方案,

由于Java fx在单线程上运行,所以一切都必须在同一个线程上。对于需要暂停背景的每个任务(例如弹出窗口),我们需要使用FutureTask。

我在这里找到了这篇文章:

JavaFX2: Can I pause a background Task / Service?

答案 2 :(得分:0)

假设您要在调用弹出窗口之前运行一些长时间运行的代码, 处理Fx按钮时,需要完成两个步骤。当按下按钮时,第一个线程使代码作为线程运行。第二个是Platform.runlater(),它告诉Fx Platform从Platform执行该线程中的代码。请注意,直到在外部线程中达到runlater后,才会执行弹出窗口。 否则,您可以直接调用弹出窗口。

public void MyExampleBtn() {
  Thread t = new Thread() {
    // long running work to be done, threaded so as not to hang the main controls.
    // .... 
    // work is done do the success popup
    @Override
      public void run() {
      Platform.runLater(new Runnable() {
       @Override
         public void run() {
           Alert alert = new Alert(AlertType.INFORMATION);
           alert.setTitle("Success!");
           alert.setHeaderText(null);
           alert.setContentText("This is my popup");
           alert.showAndWait();
         }
       });
     }
   };
}