So I followed this tutorial: https://www.youtube.com/watch?v=gyyj57O0FVI
and I made exactly the same code in javafx8.
public class CountdownController implements Initializable{
@FXML
private Label labTime;
@Override
public void initialize(URL location, ResourceBundle resources) {
new Thread(){
public void run(){
while(true){
Calendar calendar = new GregorianCalendar();
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
String time = hour + ":" + minute + ":" + second;
labTime.setText(time);
}
}
}.start();
}
After I close the Window, application/thread is still running in the system. My guess its because the infinite loop, but shouldnt the thread be terminated with application closing?
Second thing is that when I try to set the text for Label I get the 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:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Parent$2.onProposedChange(Parent.java:364)
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$60(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$$Lambda$144/1099655841.call(Unknown Source)
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:143)
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:146)
at application.CountdownController$1.run(CountdownController.java:29)
...yes, I am going to read more about threads, but I would like to know the answer to these questions.
Part I
A thread, when created, runs independent of other threads. You have a new thread which has an infinite loop, which implies, it will keep running forever, even after the stage has been closed.
Normally, using a infinite loop is not advised, because breaking out of it is very difficult.
You are advised to use :
You can then call either one of them (based on whatever you are using)
when your stage is closed. You can use something like :
JavaFX API's (thanks to James_D comment's)
These do not need to be explicitly canceled as
ScheduledService
uses daemon threads andAnimationTimer
runs on the JavaFX thread.Part II
Your second part of the question has been answered time and again in the forum.
Since you have created a new thread and trying to update
label
, which is a JavaFX node, it throws the exception. For more information, please visit:JavaFX error when trying to remove shape
Why am I getting java.lang.IllegalStateException "Not on FX application thread" on JavaFX?
Javafx Not on fx application thread when using timer
With
ScheduledExecutorService
as far as I am concerned You cant easly set it as deamon and I don't want to play withstage.setOnCloseRequest(closeEvent -> {});
With AnimationTimer I cant do something like
Thread.sleep(100)
beetween iteration like you suggested because "AnimationTimer runs on the JavaFX thread."ScheduledService
is just quite difficult for me to understand right now...so, as I was reading and reading about it I came to conclusion that maybe this simple option will be the best:
Thanks James_D and ItachiUchiha. It works, let me know if I'am something missing!
EDIT: I also include code for Counting down the time, as it was my initial aim, maybe someone will find it usefull as well: