0

How can I change a scene without directly interacting with it (like using a button). What I would like for my program to do is change scene, and then using the Initializable class, the program would wait 1.5 seconds then change scene.

I am currently using a PauseTransition to do this, however I get a ClassCastException. Also, I do not understand what Intellij is trying to tell me about the Node. It says 'Find why 'event.getSource()' could be javafx.animation.PauseTransition (not-null)'.

Thanks in advance.

Stack Trace:

Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class javafx.animation.KeyFrame cannot be cast to class javafx.scene.Node (javafx.animation.KeyFrame and javafx.scene.Node are in module javafx.graphics of loader 'app')
    at Dice.Game/sample.RoundCounterController.lambda$initialize$0(RoundCounterController.java:54)
    at javafx.graphics/com.sun.scenario.animation.shared.TimelineClipCore.visitKeyFrame(TimelineClipCore.java:239)
    at javafx.graphics/com.sun.scenario.animation.shared.TimelineClipCore.playTo(TimelineClipCore.java:180)
    at javafx.graphics/javafx.animation.Timeline.doPlayTo(Timeline.java:177)
    at javafx.graphics/javafx.animation.AnimationAccessorImpl.playTo(AnimationAccessorImpl.java:39)
    at javafx.graphics/com.sun.scenario.animation.shared.SingleLoopClipEnvelope.timePulse(SingleLoopClipEnvelope.java:99)
    at javafx.graphics/javafx.animation.Animation.doTimePulse(Animation.java:1101)
    at javafx.graphics/javafx.animation.Animation$1.lambda$timePulse$0(Animation.java:186)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/javafx.animation.Animation$1.timePulse(Animation.java:185)
    at javafx.graphics/com.sun.scenario.animation.AbstractMasterTimer.timePulseImpl(AbstractMasterTimer.java:344)
    at javafx.graphics/com.sun.scenario.animation.AbstractMasterTimer$MainLoop.run(AbstractMasterTimer.java:267)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:515)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:499)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:492)
    at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:320)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:829)

RoundCountController.java

import javafx.animation.KeyFrame;
import javafx.animation.PauseTransition;
import javafx.animation.Timeline;
import javafx.animation.Transition;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

public class RoundCounterController implements Initializable {
    @FXML private Label roundLabel;
    private static int roundCounter = 0;
    @FXML private AnchorPane pane;

    private Stage stage;
    private Scene scene;
    private Parent root;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        PauseTransition pauseTransition = new PauseTransition(Duration.seconds(1.5));
        pauseTransition.setOnFinished(event -> {
            try {
                Parent root = FXMLLoader.load(getClass().getResource("p1GameScene.fxml"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
            scene = new Scene(root);
            stage.setScene(scene);
            stage.show();
        });
        pauseTransition.play();
        
    }
}
Dan J
  • 11
  • 4
  • I don't advise calling `getClass()` in a lambda [it isn't going to return the class you think it will](https://stackoverflow.com/questions/34589435/get-the-enclosing-class-of-a-java-lambda-expression). Instead, reference the class by name, (e.g. `RoundCounterController.class.getResource()`). I also advise [troubleshooting resource lookup](https://stackoverflow.com/questions/19602727/how-to-reference-javafx-fxml-files-in-resource-folder). – jewelsea Sep 07 '21 at 20:46
  • Your source code doesn't match your exception trace. The trace references line 54 and the source is only 49 lines long. – jewelsea Sep 07 '21 at 20:48
  • Yes, note that is likely not your actual primary issue here. – jewelsea Sep 07 '21 at 20:51
  • Getting a node from the event source within a PauseTransition also seems like an iffy thing to do. A PauseTransition is not triggered by a user interaction event, so I don't know why the source of that event would be a node. – jewelsea Sep 07 '21 at 20:53
  • @jewelsea You are right, I must have tinkered a bit, so running it again line 41 was the issue `stage = (Stage) ((Node) event.getSource()).getScene().getWindow();` – Dan J Sep 07 '21 at 20:53
  • This won't work: `(Stage) ((Node) event.getSource()).getScene().getWindow()`. The source of the event in this case seems to be a `KeyFrame` (probably `PauseTransition` uses something like a `Timeline` as part of the implementation, though if it were consistent then the source should be the `PauseTransition` itself). Note the event fired to the `onFinished` handler is not associated with a view, unlike when you add an `onAction` handler to e.g. a `Button`. – Slaw Sep 07 '21 at 20:53
  • @Slaw Is there an alternative way I can change scene without that line? – Dan J Sep 07 '21 at 20:56
  • 3
    In your case you could probably do `stage = (Stage) pane.getScene().getWindow()`. – Slaw Sep 07 '21 at 20:56
  • @Slaw Thank you so much it works! Could you please explain what this line does? – Dan J Sep 07 '21 at 20:59
  • 1
    When you used a `Button` for this, the source of the event was said button. So your code was getting the scene of the button, and then getting the window of that scene. You then replace the scene with a new one. Since you're now using a `PauseTransition` you don't have access to the button (in fact, the button likely no longer exists at all in your case). So you need to find another way to do essentially the same thing. You're injecting an `AnchorPane` into the `pane` field. You can use that to accomplish your goal, as presumably you're adding the nodes created by the FXML to the same window. – Slaw Sep 07 '21 at 21:02
  • @Slaw Thanks for explaining, I mostly understand! – Dan J Sep 07 '21 at 21:05

0 Answers0