-1

(Code at bottom) Part of an application I'm trying to make involves a timer and I want to be able to display this timer in the bottom corner of the application. I've made a thread that will count down from a given number (in seconds) and display the countdown in the command line.

The problem is, I am unsure how to send this value back to my controller. I have tried to do this by saving the controller as a static variable in another class so methods and variables and so on can be accessed, but this also does not work as I get this error:

Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:444)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$0(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
at train.TrainController.updateTime(TrainController.java:34)
at train.Timerr.run(Timerr.java:36)

I think I need to add a listener within the controller but I'm not sure how to do this.

Here I will make a quick example of what I want to do. Everything is just in one package of a new javaFX project. The error I get here is the exact same:

Main:

public class Quick extends Application {

@Override
public void start(Stage primaryStage) throws IOException{
    FXMLLoader loader = new FXMLLoader(getClass().getResource("FXML.fxml"));
    Parent root = loader.load();
    Master.savedController = loader.getController();
    Scene scene = new Scene(root, 200, 200);
    
    primaryStage.setTitle("KReact");
    primaryStage.setScene(scene);
    primaryStage.setResizable(false);
    
    primaryStage.show();
}

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    launch(args);
}

}

Master class:

public class Master {

public static FXMLController savedController;

}

Thread:

public class Timerr extends Thread{

public int t;

Timerr(int time){
    t = time;
}

@Override
public void run(){
    
    while(t > 0){
        try{
            Thread.sleep(1000);
            t = t-1;
        }catch(InterruptedException e){}

        System.out.println(t);
        Master.savedController.updateTime(t);
    }
    
}

}

Controller:

public class FXMLController implements Initializable {

@FXML Label time;

public void updateTime(int t){
    time.setText(Integer.toString(t));
}

Timerr timer = new Timerr(60);

@FXML public void start(){
    timer.start();
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    time.setText("60");
}    

}

FXML file:

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" fx:controller="quick.FXMLController">
<Label fx:id="time" layoutX="80" layoutY="80"/>
<Button onAction="#start"/>

I haven't been able to find the answer anywhere, and I thought it would be best to give an example code in case it is helpful to answer my question.

Thank you very much in advance for taking a look :)

Edit: think there may be something with Task I can do, but still couldn't find what.

Owen Cook
  • 43
  • 3
  • 1
    If you are genuinely trying to update the UI at regular intervals, don't use background threads at all; use animations. See https://stackoverflow.com/questions/9966136/javafx-periodic-background-task, among many, many other similar questions. – James_D Jun 23 '20 at 12:39

1 Answers1

0

Using timelines instead of a thread fixed this: JavaFX periodic background task

Owen Cook
  • 43
  • 3