Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'Not on FX application thread' error when starting thread from dialog with loaded FXML as content

I currently have the following situation:

I have created a JavaFX application, which contains a screen from which I open a dialog (just by clicking a button on the screen). Then, the user gives input and clicks the apply button. The user input is then sent to a method, which opens some sort of progress dialog (for showing the user the status of the synchronization, which is not important for the problem). I will call this dialog 'MyDialog'. MyDialog is built with the following code:

Dialog<Void> dialog = new Dialog<>();
dialog.initOwner(null);
dialog.initStyle(StageStyle.UNDECORATED);
dialog.setHeaderText("Nieuw product synchroniseren...");
dialog.setResizable(false);

//Load dialog FXML file into the Pane
FXMLLoader fxmlloader = new FXMLLoader();
fxmlloader.setLocation(getClass().getResource("dialogs/MyDialogContent.fxml"));
try {
    dialog.getDialogPane().setContent(fxmlloader.load());
} catch (IOException e) {
    Functions.createExceptionDialog(e);
}
MyDialogContentController childController = fxmlloader.getController();

final ButtonType canceledButtonType = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE);
dialog.getDialogPane().getButtonTypes().add(canceledButtonType);

This works just fine. The ProgressBar, which is shown in MyDialog, indicated the progress of a task. The task is started from a thread. This thread is started from the controller of the upper screen. From within the task, I would like to show an additional dialog at some point, to get some user validation. I will call this dialog 'AlertDialog'. This is the code for that part (which is placed in the Controller of the upper screen, and not in the Controller of MyDialog):

Task<Object> task = new Task<Object>() {

    @Override
    protected Object call() {
        //Show choice dialog
        Alert alert = new Alert(AlertType.CONFIRMATION);
        alert.initOwner(null);
        alert.initStyle(StageStyle.UNDECORATED);

        ButtonType buttonTypeOne = new ButtonType("One");
        ButtonType buttonTypeTwo = new ButtonType("Two");
        ButtonType buttonTypeThree = new ButtonType("Three");
        ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE);

        alert.getButtonTypes().setAll(buttonTypeOne, buttonTypeTwo, buttonTypeThree, buttonTypeCancel);

        Optional<ButtonType> result = alert.showAndWait();

        if (result.get() == buttonTypeOne){
            //User chose "One";
        } else if (result.get() == buttonTypeTwo) {
            // ... user chose "Two"
        } else if (result.get() == buttonTypeThree) {
            // ... user chose "Three"
        } else {
            // ... user chose CANCEL or closed the dialog
        }
    }
}

Unfortunately, the AlertDialog is not showing, and I get the following error:

Exception in thread "Thread-10" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-10

I already tried the following solutions:

  • Place the AlertDialog code in the MyDialogController, and then call it from the task.
  • Start the thread from MyDialogController, instead of starting in from the upper screen controller. And then call it by 'childController.thread'.

Both of these solutions did not work. I expect it has something to do with loading the FXML file in the DialogPane, and therefore with the thread and from where it is started.

So the questions in this situation are:

  1. Why do I get this error?

  2. Has the error something to do with the AlertDialog not showing?

  3. Should my approach for this part of the code be different? (e.g. without loading an external FXML file in a dialog)

Any help is greatly appreciated!

like image 974
bashoogzaad Avatar asked Sep 07 '25 18:09

bashoogzaad


1 Answers

I feel like I have written this 100 times on SO.. yet again: JavaFX is a single threaded GUI tookit, thus every thing GUI related has to be done on the main JavaFX Thread.

If you try to do something GUI related out of the JavaFX Thread you will get your IllegalStateException: Not on FX application thread.

Optional<ButtonType> result = alert.showAndWait(); is a GUI action because you initialize and show a Dialog. So you should retrieve your user input somewhere else and only do the long-running computations in background.

Good points for user input are for example the various life-cycle hooks of the Task class (like succeeded() or failed()).

like image 107
eckig Avatar answered Sep 09 '25 16:09

eckig