1

Hi I have application which runs both on GUI(Java FX) as well as command line. When run as GUI, i show the status on text area. This works fine.

But the issue is when ever i try to show a error(via popup) from some different (non javafx) class, it shows me Java Fx - thread Exception not on FX thread.

Below is my code

This is my Java FX class where I wish to show popup.

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

}

I have a non FX class which is the entry point. So Based on type of run (command line / GUI ) I update the status.

Here is how I am calling to update the status.

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

I have no issues when i call the updateGUIMessage method from non fx class. This is because the statusArea element is on FX thread(member of this fx class).

Also I have no issues to generate a alert box on some button click, but to display an Alert box from a different class- I am having issues since as soon as I try to generate a alert box , the application crashes, saying not on fx thread.

I understand that the Alert box is a popup and therefore may be unhandled. But can anyone help me, I want to show user a alert box, from different class.

Prateek Mishra
  • 1,226
  • 10
  • 21
  • Any class is free to call any JavaFX class or method, but that call has to be done on the Java FX thread, no matter what class makes the call. If you don’t want a particular class to import Platform, write a method in a different class which makes use of Platform.runLater, and have the “non fx” class call that method. – VGR Jun 13 '16 at 16:02

3 Answers3

3

Assuming that you want some long running code to run before the popup is called, There are two steps that need to be done when dealing with the Fx Buttons. The first thread lets the code run as a thread when the button is pushed. The second is the Platform.runlater() which is telling the Fx Platform to execute the code in that thread from the Platform. Note that the popup will not get executed until the runlater is reached in the outer thread. Otherwise you can call the popup directly.

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();
         }
       });
     }
   };
}
The CTO
  • 71
  • 3
2

Everything in the UI has to be executed from the UI application thread. That is exactly what the error message means.

Fortunately you can simply wrap your call so that it is executed in the UI thread:

if(isCommandLineRun) {
    System.out.println(simpleDateFormat.format(new Date()) + " - " + message);
} else {
    Platform.runLater(() -> controller.displayAlertMessages(message));
}
hotzst
  • 7,238
  • 9
  • 41
  • 64
  • Did not work, First of all, promptUser method is in a NON Java FX class, so I have to import Platform (which I do not want to - Intend to keep JavaFX classes in seperate class). Also after trying this my application crashes and does not show popup. Exception : java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-6 – Prateek Mishra Jun 13 '16 at 14:45
  • Also Platform.runLater shoud be used for small operations, I want to display a alert box, in which i will use showaAndWait() , so using Platform.runLater is not advisable – Prateek Mishra Jun 13 '16 at 15:14
  • When calling the method `controller.displayAlertMessages` the update has to happen on the UI thread. So you can move the call of `Platform.runLater` to the other side and only wrap that part of the code that actually updates the UI. – hotzst Jun 13 '16 at 16:32
0

Finally found the solution to it,

Since Java fx runs on single thread, everything has to be on same thread. For every task (such as popup) where there needs background to pause, we need to use FutureTask.

I found this article, here :

JavaFX2: Can I pause a background Task / Service?

Community
  • 1
  • 1
Prateek Mishra
  • 1,226
  • 10
  • 21