-2

i have scene 1 and and wrote below code to this scene 1 goes to another scene 2:

main class:

public class ProjectSeventh extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("/FXMLfiles/FXMLDocument.fxml"));

        Scene scene = new Scene(root);
     

        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

sceneOne Controlled code:

public class FXMLDocumentController implements Initializable {

    @FXML Label itemCouner;
    
    
    public void frize(Event event) throws IOException {
        FXMLLoader watingLoader = new FXMLLoader();
        watingLoader.setLocation(getClass().getResource("/FXMLfiles/wating.fxml"));
        Parent watingParent = watingLoader.load();
        Scene watingScene = new Scene(watingParent);
        Stage watingStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
        watingStage.setScene(watingScene);
        watingStage.show();
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        Random myRand = new Random();
        int holdingFrizes = myRand.nextInt(2);   
    }

}

i want to when scene 2 comes up, automaticly after 6 seconds scene 2 goes back to scene 1 without any event! but this switch scene protocol i learn needs an event at "(Node) event.getSource()" what should i do?

scene2 controller code:

public class WatingController implements Initializable {

    
    
    
public void getBackPreviousScene() throws IOException{
   PauseTransition myPouse = new PauseTransition();
   myPouse.setDuration(javafx.util.Duration.seconds(6));
    myPouse.setOnFinished((event) -> {
       try {
           FXMLLoader shopingLoader = new FXMLLoader();
           shopingLoader.setLocation(getClass().getResource("/FXMLfiles/FXMLDocument.fxml"));
           Parent shopingParent = shopingLoader.load();
           Scene shopingScene = new Scene(shopingParent);
           Stage shopingStage = (Stage) ((Node) event.getSource()).getScene().getWindow();
           shopingStage.setScene(shopingScene);
           shopingStage.show();
       } catch (IOException ex) {
       }
    });
    myPouse.play();
}
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
    try {
        getBackPreviousScene();
    } catch (IOException ex) {
    }
        
    }    

    
    
}
    
  • Why do you think you need an event? – James_D May 12 '21 at 14:57
  • how i should switch scene 2 to 1 automatically then? i dont know any other way to change scenes –  May 12 '21 at 14:59
  • Use a `PauseTransition` and switch scenes in the `onFinished` handler. – James_D May 12 '21 at 15:00
  • i edited my code, add scene 2 controller, i did what you say, i got "javafx.animation.PauseTransition cannot be cast to javafx.scene.Node " –  May 12 '21 at 15:27
  • Why are you trying to get the stage again? It's the same stage. – James_D May 12 '21 at 15:27
  • they are different scenes, scene1 is /FXMLfiles/FXMLDocument.fxml and scene2 is /FXMLfiles/wating.fxml –  May 12 '21 at 15:29
  • But you're surely using the same stage? In the first time you change scenes, you set the scene in the stage in which the event occurred. So it's the stage that's already showing. – James_D May 12 '21 at 15:30
  • its two different controller class, one for FXMLDocument.fxml and second for wating.fxml, i learn this code for switching scenes, it doesn`t make any different change stage name its just a name yes? sorry i am new to javafx –  May 12 '21 at 15:34
  • 2
    Create and post a [mre]. It's not at all clear what the issue is. You can get the stage from any node that's displayed, you don't need to get it from the event. But you can also start the pause transition in the same code block where you handle the event and switch to the second scene. Again, it's completely unclear what the problem is. You only have one stage. – James_D May 12 '21 at 15:36
  • It's also not clear why you are calling `watingStage.show()`, since it must already be showing. Or, come to that, why you are creating new `Scene`s in the first place, why not just change the root of the existing scene? – James_D May 12 '21 at 15:38
  • is it now clear? –  May 12 '21 at 15:48
  • It's clear why you're getting the exception (the source of the event is not a node). It's not clear why you're doing it like this. Just move the code in `getBackPreviousScene()` to the end of the `frize()` method (after you, for no good reason since the stage is already showing, call `watingStage.show()`). Then you already have a perfectly good reference to the stage, there's no need to try to get it from the event. – James_D May 12 '21 at 15:59
  • Does this answer your question? [How to use PauseTransition method in JavaFX?](https://stackoverflow.com/questions/30543619/how-to-use-pausetransition-method-in-javafx) – SedJ601 May 12 '21 at 20:02

1 Answers1

1

Your code generates a ClassCastException in the onFinished handler defined in getBackPreviousScene(), because the source of the event is the PauseTransition, which is not a Node. It doesn't have a Scene or access to one.

First, using the source of the event in general is not a very good way to access the scene. Instead, you can simply call getScene() on any of the injected nodes in the controller. E.g.:

public class FXMLDocumentController implements Initializable {

    @FXML Label itemCouner;
    
    
    public void frize(Event event) throws IOException {
        FXMLLoader watingLoader = new FXMLLoader();
        watingLoader.setLocation(getClass().getResource("/FXMLfiles/wating.fxml"));
        Parent watingParent = watingLoader.load();
        Scene watingScene = new Scene(watingParent);

        Stage watingStage = (Stage)itemCouner.getScene().getWindow();

        watingStage.setScene(watingScene);
        // watingStage.show();
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        Random myRand = new Random();
        int holdingFrizes = myRand.nextInt(2);   
    }

}

Note also that if you're getting the window containing a scene containing a node on which an event occurred, that window must necessarily already be showing, so there's no point at all in calling

watingStage.show();

in the code above. You could do the same in your WatingController by injecting some node into the controller.

Second, the WatingController seems to be the wrong place to control how long the UI declared in the FXML is displayed. This should be the responsibility of the code that displays it, which in this case is the frize() method in the FXMLDocumentController class. In particular, this makes it impossible to load the FXML ahead of time and display it later, because after six seconds calling getScene().getWindow() would throw a null pointer exception.

So, e.g., you could do:

public class FXMLDocumentController implements Initializable {

    @FXML Label itemCouner;
    
    
    public void frize(Event event) throws IOException {
        FXMLLoader watingLoader = new FXMLLoader();
        watingLoader.setLocation(getClass().getResource("/FXMLfiles/wating.fxml"));
        Parent watingParent = watingLoader.load();
        Scene watingScene = new Scene(watingParent);

        Scene currentScene = itemCouner.getScene();
        Stage stage = (Stage) currentScene.getWindow();
        
        stage.setScene(watingScene);

        PauseTransition pause = new PauseTransition(Duration.seconds(6));
        pause.setOnFinished(e -> stage.setScene(currentScene));
        pause.play();
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
    }

}

And then the code in your WatingController can all be removed.

Finally, note that in your example there seems to be no need at all to create new scenes. Just replace the root of the existing scene:

public class FXMLDocumentController implements Initializable {

    @FXML Label itemCouner;
    
    
    public void frize(Event event) throws IOException {
        FXMLLoader watingLoader = new FXMLLoader();
        watingLoader.setLocation(getClass().getResource("/FXMLfiles/wating.fxml"));
        Parent watingParent = watingLoader.load();

        Scene currentScene = itemCouner.getScene();
        Parent currentRoot = currentScene.getRoot();
        
        currentScene.setRoot(watingParent);

        PauseTransition pause = new PauseTransition(Duration.seconds(6));
        pause.setOnFinished(e -> currentScene.setRoot(currentRoot));
        pause.play();
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
    }

}

Complete example:

primary.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>

<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.jamesd.examples.tempscene.PrimaryController">
   <children>
      <Button fx:id="showTempButton" text="Show Temporary View" onAction="#showTemp"/>
   </children>
   <padding>
      <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
   </padding>
</VBox>

PrimaryController.java:

package org.jamesd.examples.tempscene;

import java.io.IOException;

import javafx.animation.PauseTransition;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.util.Duration;

public class PrimaryController {
    
    @FXML
    private Button showTempButton ;

    @FXML
    private void showTemp() throws IOException  {
        
        Scene currentScene = showTempButton.getScene();
        Parent currentRoot = currentScene.getRoot();
        
        FXMLLoader loader = new FXMLLoader(getClass().getResource("temp.fxml"));
        Parent tempRoot = loader.load();
        
        currentScene.setRoot(tempRoot);
        
        PauseTransition pause = new PauseTransition(Duration.seconds(2));
        pause.setOnFinished(e -> currentScene.setRoot(currentRoot));
        pause.play();
    }
}

temp.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>

<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" >
    <children>
        <Label text="Temporary View" />
    </children>
    <padding>
        <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
    </padding>
</VBox>

App.java:

package org.jamesd.examples.tempscene;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;


public class App extends Application {

    private static Scene scene;

    @Override
    public void start(Stage stage) throws IOException {
        scene = new Scene(FXMLLoader.load(getClass().getResource("primary.fxml")), 640, 480);
        stage.setScene(scene);
        stage.show();
    }


    public static void main(String[] args) {
        launch();
    }

}
James_D
  • 201,275
  • 16
  • 291
  • 322