Why am I Getting Java.Lang.Illegalstateexception "Not on Fx Application Thread" on Javafx

Why am I getting java.lang.IllegalStateException Not on FX application thread on JavaFX?

The user interface cannot be directly updated from a non-application thread. Instead, use Platform.runLater(), with the logic inside the Runnable object. For example:

Platform.runLater(new Runnable() {
@Override
public void run() {
// Update UI here.
}
});

As a lambda expression:

// Avoid throwing IllegalStateException by running from a non-JavaFX thread.
Platform.runLater(
() -> {
// Update UI here.
}
);

Not on FX application thread; currentThread = Thread-5

The only thread that is allowed to modify the JavaFX GUI is the JavaFX thread. If any other thread modifies the UI, you will get an exception.

The most simple answer to this common problem is to wrap the code that changes the GUI in Platform.runLater(). Be careful not to put any sleeps in the runlater(), as they will cause the JavaFX GUI thread to sleep, which will cause your program to freeze for the duration of the sleep.

Platform.runLater() has the following javadoc:

Run the specified Runnable on the JavaFX Application Thread at some
unspecified time in the future. This method, which may be called from
any thread, will post the Runnable to an event queue and then return
immediately to the caller. The Runnables are executed in the order
they are posted. A runnable passed into the runLater method will be
executed before any Runnable passed into a subsequent call to
runLater. If this method is called after the JavaFX runtime has been
shutdown, the call will be ignored: the Runnable will not be executed
and no exception will be thrown.

NOTE: applications should avoid flooding JavaFX with too many pending
Runnables. Otherwise, the application may become unresponsive.
Applications are encouraged to batch up multiple operations into fewer
runLater calls. Additionally, long-running operations should be done
on a background thread where possible, freeing up the JavaFX
Application Thread for GUI operations.

This method must not be called before the FX runtime has been
initialized. For standard JavaFX applications that extend Application,
and use either the Java launcher or one of the launch methods in the
Application class to launch the application, the FX runtime is
initialized by the launcher before the Application class is loaded.
For Swing applications that use JFXPanel to display FX content, the FX
runtime is initialized when the first JFXPanel instance is
constructed. For SWT application that use FXCanvas to display FX
content, the FX runtime is initialized when the first FXCanvas
instance is constructed.

I don't think your code is structured in the best way to accomplish this task, but a very simple solution is the following:

new Thread(()->{
statusBarShow();
}).start();

private void statusBarShow(){
try {
Platform.runLater(()->statusLable.setText("Tip 1"));
Thread.sleep(2000);
Platform.runLater(statusLable.setText("Tip 2"));
Thread.sleep(2000);
Platform.runLater(statusLable.setText("Tip 3"));
Thread.sleep(2000);
Platform.runLater(statusLable.setText("Tip 4"));
Thread.sleep(2000);
Platform.runLater(statusLable.setText("Tip 5"));
} catch (Exception e) {
e.printStackTrace();
}
}

A better solution to your problem may be to use an AnimationTimer.

Here is a useful thread on how to accomplish that: JavaFX periodic background task

IllegalStateException when using JavaFX Alert in init() because not on FX application thread

In the past I've been able to solve this kind of issues with wrapping the logic in a Platform.runLater() call. ie:

try {
[...]
} catch (Exception e) {
Platform.runLater(new Runnable() {
@Override public void run() {
new Alert(AlertType.ERROR).showAndWait();
Platform.exit();
});
}

I use this approach every time I need to do some work that's not directly related to what's going on in the interface.

As taken from the wiki :

public static void runLater(Runnable runnable)

Parameters:

runnable - the Runnable whose run method will be executed on the JavaFX Application Thread

How to solve (java.lang.IllegalStateException: Not on FX application thread)?

You code is conceptually wrong. Platform.runLater executes the given code on the FX application thread but you do not want to put the timer scheduling on that thread. Instead the code that is run by the timer must be wrapped in Plaform.runLater because it sets the label which has to happen on the FX application thread.

Why am I getting “Not on FX application thread” on JavaFX?

To flesh out my comment: if you want to keep the model completely unaware of the UI, then don't bind it directly to a property of a control. Instead, on the UI side have some listener to the model property that changes the control property on the fx thread.

A code snippet (not tested, just copied and adjusted - so might not even compile ;):

public void setModel(Temp aTemp) {
this.aTemp = aTemp;

aTemp.tempProperty().addListener(this::updateLabelText)

}}

private void updateLabelText() {
Platform.runLater(() -> label.setText(aTemp.getTemp()));
}

java.lang.IllegalStateException:Not on FX application when using quartz

JavaFX, like most UI toolkits, is single-threaded and not thread-safe. Once a scene graph is being displayed in a window, it must only be interacted with on the JavaFX Application Thread. And some objects must be instantiated on the FX thread. To do otherwise can lead to errors, as you've encountered, or just full on undefined behavior. If you're on a background thread and you need to schedule an action with the FX thread, you can use Platform.runLater(Runnable) (link is to the Javadoc).

Your code is not a minimal and complete example, so I can't be sure of what everything does. In general, however, I would start by moving all the code relating to Alert instances into a runLater call.

public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Executou!");
try {
String verStatus = "SELECT COUNT(*) FROM equipamento_requisicao";
PreparedStatement stmt = con.prepareStatement(verStatus);
ResultSet rsStatus = stmt.executeQuery();
if (rsStatus.next()) {
Alerts a = new Alerts(); // what does this do?
int Resultado = rsStatus.getInt(1);
if (Resultado > Sessao.getInstancia().getQtdRegistroBD()) {
Sessao.getInstancia().setQtdRegistroBD(Resultado); // unknown side-effects
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("SUCESS");
alert.setHeaderText("SUCESS");
alert.setContentText("SUCESS");
alert.showAndWait();
});
} else if (Resultado < Sessao.getInstancia().getQtdRegistroBD()) {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("FAIL");
alert.setHeaderText("FAIL");
alert.setContentText("FAIL");
alert.showAndWait();
});
Sessao.getInstancia().setQtdRegistroBD(Resultado); // unknown side-effects
} else {
//aq não irei fazer nada.
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

Some notes:

  • The above uses lambda expressions.
  • Don't forget to close resources (e.g. PreparedStatement, ResultSet) when done with them. Use try-with-resources.
  • The calls to runLater do not wait for the Runnable to return.
  • The "unknown side-effects" comments are there because I have no idea if those method invocations modify the UI. I've left them out of the runLater call on the assumption that they don't.
  • I couldn't find where Alerts a = new Alerts() is actually used.
  • The name Resultado does not follow standard Java naming conventions for local variables.
  • Notice that properly indenting your code makes it much easier to read and follow what is happening.

I am new to java and do not understand much about threads

Not having at least a basic understanding of concurrency in Java will hinder your efforts to create all but the most trivial of GUI applications. I highly recommend you study this topic before moving forward. As a start, read these:

  • Lesson: Concurrency
  • Concurrency in JavaFX

Also, a good book on the topic is Java Concurrency in Practice by Brian Goetz et al.

java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4

Wrap timer.setText() in Platform.runLater(). Outside it, inside the while loop, add Thread.sleep(1000);

The reason behind Illegal State Exception is you are trying to update UI on some thread other than JavaFX Application thread.

The reason why your app was crashing when you added it was you were overloading the UI thread by adding a process to be executed on the UI thread infinitely. Making the thread sleep for 1000ms will help you overcome the issue.

If possible replace while(true) with a Timer or TimerTask.

For more options follow this link

Not on FX application thread Exception. When I try call Pane.getChildren().add() from Thread

I have solved it this way.

I use "new Timer().schedule()" instead "Thread" plus Platform.runLater() inside this timer.

This way paths change OK.

package Fx;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import java.util.*;

public class SkladPlanFx extends Application {

static int test = 0;
Path path;

public static void main(String[] args) {
SkladPlanFx.launch(SkladPlanFx.class, args);
}

@Override
public void start(Stage primaryStage) {

Text text = new Text();

text.setText("qqq");
text.setLayoutX(450);
text.setLayoutY(800);

Pane root = new Pane();
Scene scene = new Scene(root, 500, 500);

primaryStage.setScene(scene);
primaryStage.show();

//Timer
new Timer().schedule(
new TimerTask() {
@Override
public void run() {
System.out.println("ping " + ++test);
text.setText(" " + test);

//here is the solution
Platform.runLater(new Runnable() {
@Override public void run() {
root.getChildren().remove(path);
test++;
//path = makePath(coordinates.subList(test, test+5));
path = makeTestPath();
root.getChildren().add(path);
}
});

}
}, 0, 1000);

}

public Path makeTestPath() {
Path path = new Path();
path.setStroke(Color.RED);
path.getElements().add(new MoveTo(getRandomNumberInRange(1, 500), getRandomNumberInRange(1, 500)));
for (int i = 0; i < 10; i++) {
path.getElements().add(new LineTo(getRandomNumberInRange(1, 500), getRandomNumberInRange(1, 500)));
}
return path;
}

private static int getRandomNumberInRange(int min, int max) {
if (min >= max) {
throw new IllegalArgumentException("max must be greater than min");
}
Random r = new Random();
return r.nextInt((max - min) + 1) + min;
}
}


Related Topics



Leave a reply



Submit