Search code examples
animationjavafxtimer

Adding a Timer in JavaFX Application for Fade Out Animation


I understand this may be a duplicate post. I will link what I've been looking as some of the sources may be wrong for this specific project.

Long story short, I'm making a game and just switched from JavaSwing to JavaFX. Currently right now, I'm making the start screen and making an attempt to try and make the screen fade out and clear itself out for the game to start. Using VBox and HBox, everything seems to be working kind of.

    public static void fadeOut() {
        FadeTransition ft = new FadeTransition(Duration.millis(3000), vb);
        ft.setFromValue(1);
        ft.setToValue(0);
        ft.play();
        
        Timer t = new Timer();
        t.schedule(new TimerTask() {
            @Override 
            public void run() {
                Ce.console.getChildren().clear();
            }
        }, 300l);
        
        
        startTrue();
    }

As of right now, the start screen fades away but doesn't clear itself from the main VBox and assuming I set up Timer() wrong, I get this error.

Exception in thread "Timer-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = Timer-0
    at [email protected]/com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:297)
    at [email protected]/com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:458)
    at [email protected]/javafx.scene.Parent$3.onProposedChange(Parent.java:474)
    at [email protected]/com.sun.javafx.collections.VetoableListDecorator.clear(VetoableListDecorator.java:293)
    at FXConsole/application.console.SS$1.run(SS.java:100)
    at java.base/java.util.TimerThread.mainLoop(Timer.java:566)
    at java.base/java.util.TimerThread.run(Timer.java:516)

I'm thinking that I'm supposed to be using an AnimationTimer()/Timeline() with KeyFrame() but I'm not sure. I'll give it more testing and see if I can come to a solution but if anyone knows a better way to approach this, the help would be greatly appreciated.

edit: Here was the main page I used for this - How to set a Timer in Java?

sorry for the inconvenience.


Solution

  • You shouldn't be using a timer here.

    If you want to do something when an animation like a transition finishes, then invoke animation.setOnFinished(eventHandler).

    For your example:

    FadeTransition ft = new FadeTransition(Duration.millis(3000), vb);
    ft.setFromValue(1);
    ft.setToValue(0);
    ft.setOnFinished(e -> Ce.console.getChildren().clear());
    ft.play();
    

    Why your Timer usage fails

    The error message you get when you use a timer:

    IllegalStateException: Not on FX application thread
    

    happens because the timer runs on its own thread and you should not modify the scene graph from another thread.

    The IllegalStateException error can be fixed by wrapping the code that executes in the timer in Platform.runLater(runnable). If you use runLater, you need to ensure that any code executed via runLater is not long-running code or IO that would block the JavaFX thread.

    However, using the in-built onFinished method is superior for numerous reasons, among them being that the onFinished handler is always run on the JavaFX thread, so you don't need to deal with potentially complicated and error-prone multi-threaded code.