Reputation: 21
I'm building app for making tests. I have a scene made in SceneBuilder. There is a ImageView under image Label with Question and 3 buttons "A", "B", "C", Texts to buttons and question's Label are taken from DataBase, if you click answer new Image, question and asnwers are loading, everything works, but i want to add a Timer in the corner. When image and question show on the screen there will be "Time to read the question" and countdown from 10 to 0, and then "Time to answer" and again countdown from 10 to 0. If timer ends and there is no answer question and image will change automaticly. But the problem is that, i can do the timer, its counting down, and after this time it change the question but I dont know how to put it into Label. If inside Timer I do something like seconds-- label.setText(seconds) there is no error but when I start app there is a lot of exceptions. Can you help me how I can put this variable which is decrementing in timer after each second to Label ?
public void setTimer() {
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if(interval > 0)
{
timeElapsed.setText("Time to read the question: "+interval);
System.out.println(interval);
interval--;
}
else
timer.cancel();
}
}, 1000,1000);
}
Now i have something like this, in console everything is working there is a countdown from 10 to 0 but no effect in scene.
And errors:
Exception in thread "Timer-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = Timer-0
at javafx.graphics/com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:291)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:493)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at javafx.controls/javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:271)
at javafx.controls/javafx.scene.control.skin.LabeledSkinBase.lambda$new$11(LabeledSkinBase.java:219)
at javafx.controls/com.sun.javafx.scene.control.LambdaMultiplePropertyChangeListenerHandler.lambda$new$1(LambdaMultiplePropertyChangeListenerHandler.java:49)
at javafx.base/javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at javafx.base/com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:181)
at javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)
at javafx.base/javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:104)
at javafx.base/javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:111)
at javafx.base/javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:145)
at javafx.base/javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:50)
at javafx.base/javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.controls/javafx.scene.control.Labeled.setText(Labeled.java:147)
at gui.controller.StudentTestYesNoController$1.run(StudentTestYesNoController.java:40)
at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
at java.base/java.util.TimerThread.run(Timer.java:506)
Upvotes: 0
Views: 12946
Reputation: 29
Adding on to what mr mcwolf said above, i think you need to set
Platform.setImplicitExit(false);
before Platform.runLater();
so that it will run every time the task is called.
Upvotes: 0
Reputation: 2859
The problem is that you are trying to change the UI from a thread other than the application.
This should solve the problems with your current implementation
public void setTimer() {
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if(interval > 0)
{
Platform.runLater(() -> timeElapsed.setText("Time to read the question: "+interval));
System.out.println(interval);
interval--;
}
else
timer.cancel();
}
}, 1000,1000);
}
Also, you can take a look at something specific about the javafx - Timeline
JavaFX periodic background task
Upvotes: 3