JavaFX,Label setText中的倒数计时器

时间:2022-07-25 17:01:20

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 ?

我正在构建用于进行测试的应用程序。我在SceneBuilder中创建了一个场景。 Image下有一个带有问题的ImageView和3个按钮“A”,“B”,“C”,文本到按钮和问题的标签是从DataBase中获取的,如果你点击回答新的图像,问题和asnwers正在加载,一切正常,但我想在角落里添加一个Timer。当图像和问题显示在屏幕上时,将有“读取问题的时间”和倒计时从10到0,然后是“回答时间”并再次从10倒数到0.如果计时器结束且没有回答问题,图像会自动改变。但问题是,我可以做计时器,它倒计时,在这之后它改变了问题,但我不知道如何将它放入标签。如果在Timer内部我做了类似秒 - label.setText(秒)的事情,那么没有错误,但是当我启动应用程序时会有很多异常。你能帮我解决一下这个变量,这个变量在每秒钟之后递归到标签吗?

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.

现在我有这样的东西,在控制台一切正常,倒计时从10到0但在场景中没有效果。

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)

1 个解决方案

#1


1  

The problem is that you are trying to change the UI from a thread other than the application.

问题是您正在尝试从应用程序以外的线程更改UI。

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的特定内容 - 时间轴

JavaFX periodic background task

JavaFX定期后台任务

#1


1  

The problem is that you are trying to change the UI from a thread other than the application.

问题是您正在尝试从应用程序以外的线程更改UI。

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的特定内容 - 时间轴

JavaFX periodic background task

JavaFX定期后台任务