Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

javafx binding throws Illegal State Exception: Not on FX Application thread

haryshOct 13 2013 — edited Oct 13 2013

Hi All,

I am trying to Update a Label from a task by using bindings.

However When I "Bind" the label's text property with a String property from the Task, Illegal State exception is thrown. Saying its not on the JavaFX thread.

The Exception occurs whenever I try to set the String property from withing the Task.

Please do not suggest to use platform.RunLater(). I want to do it through bindings as the values I am trying to display in the label ( later on ) might change too frequently and i don't want to flood the UI thread's queue with runnable objects.

Please let me know what I am doing wrong and what I have to change to make it work properly with bindings. ( I am new to bindings and the JavaFx Concurrency API )

Below is my Code.

public class MyTask extends Task<String>{

    MyTask(){

       System.out.println("Task Constructor on Thread "+Thread.currentThread().getName());

    }

    private StringProperty myStringProperty = new SimpleStringProperty(){

        {

            System.out.println("Creating stringProperty on Thread "+Thread.currentThread().getName());

        }

    };

    private final void setFileString(String value) {

        System.out.println("Setting On Thread"+Thread.currentThread().getName());

        myStringProperty.set(value); }

    public final String getFileString() { return myStringProperty.get(); }

    public final StringProperty fileStringProperty() {

        System.out.println("Fetching property On Thread"+Thread.currentThread().getName());

        return myStringProperty; }

   

    @Override

    public String call() throws Exception{

        System.out.println("Task Called on thread "+Thread.currentThread().getName());

       for(int counter=0;counter<100;counter++){

           try{

           setFileString(""+counter);

           }catch(Exception e){

               e.printStackTrace();

           }

           Thread.sleep(100);

           System.out.println("Counter "+counter);

       }

       return "COMPLETED";

    }

}

public class MyService extends Service<String> {

    MyTask myTask;

    public MyService(){

        System.out.println("Service Constructor on Thread "+Thread.currentThread().getName());

        myTask=new MyTask();

    }

    @Override

    public Task createTask(){

        System.out.println("Creating task on Thread "+Thread.currentThread().getName());

        return myTask;

    }

}

public class ServiceAndTaskExperiment extends Application {

    @Override

    public void start(Stage stage) throws Exception {

        Parent root = FXMLLoader.load(getClass().getResource("Sample.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);

        stage.show();

    }

    public static void main(String[] args) {

        launch(args);

    }

}

public class SampleController implements Initializable {

    @FXML

    private Label label;

    @FXML

    private void handleButtonAction(ActionEvent event) {

        System.out.println("You clicked me!");

        myTestService.start(); //This will throw out exceptions when the button is clicked again, it does not matter

    }

    MyService myTestService=new MyService();

    @Override

    public void initialize(URL url, ResourceBundle rb) {

        label.setText("Hello World!");

        //adding the below Line causes the exception

        label.textProperty().bind(myTestService.myTask.fileStringProperty()); //removing this line removes the exception, ofcourse the label wont update.

    }

}

//sample.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>

<?import java.util.*?>

<?import javafx.scene.*?>

<?import javafx.scene.control.*?>

<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml" fx:controller="serviceandtaskexperiment.SampleController">

    <children>

        <Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />

        <Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />

    </children>

</AnchorPane>

And this is the output with the bindings on:

Output: when binding is enabled label.textProperty().bind(myTestService.myTask.fileStringProperty());

Service Constructor on Thread JavaFX Application Thread

Creating stringProperty on Thread JavaFX Application Thread

Task Constructor on Thread JavaFX Application Thread

Fetching property On ThreadJavaFX Application Thread

You clicked me!

Creating task on Thread JavaFX Application Thread

Task Called on threadThread-4

Setting On ThreadThread-4

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

at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:237)

  at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:398)

  at javafx.scene.Parent$1.onProposedChange(Parent.java:245)

  at com.sun.javafx.collections.VetoableObservableList.setAll(VetoableObservableList.java:90)

  at com.sun.javafx.collections.ObservableListWrapper.setAll(ObservableListWrapper.java:314)

  at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:602)

  at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:209)

  at com.sun.javafx.scene.control.skin.SkinBase$3.changed(SkinBase.java:282)

  at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:107)

  at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)

  at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)

  at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:121)

  at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:128)

  at javafx.beans.property.StringPropertyBase.access$100(StringPropertyBase.java:67)

  at javafx.beans.property.StringPropertyBase$Listener.invalidated(StringPropertyBase.java:236)

  at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)

  at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)

  at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:121)

  at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:128)

  at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:161)

  at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:67)

  at serviceandtaskexperiment.MyTask.setFileString(MyTask.java:24)

  at serviceandtaskexperiment.MyTask.call(MyTask.java:36)

  at serviceandtaskexperiment.MyTask.call(MyTask.java:11)

  at javafx.concurrent.Task$TaskCallable.call(Task.java:1259)

  at java.util.concurrent.FutureTask.run(FutureTask.java:262)

  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)

  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)

  at java.lang.Thread.run(Thread.java:724)

Output with the bindings Removed: ( label wont update )

Service Constructor on Thread JavaFX Application Thread

Creating stringProperty on Thread JavaFX Application Thread

Task Constructor on Thread JavaFX Application Thread

You clicked me!

Creating task on Thread JavaFX Application Thread

Task Called on threadThread-4

Setting On ThreadThread-4

Counter 0

Setting On ThreadThread-4

Counter 1

Setting On ThreadThread-4

Counter 2

Setting On ThreadThread-4

This post has been answered by James_D on Oct 13 2013
Jump to Answer
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Nov 10 2013
Added on Oct 13 2013
1 comment
3,812 views