Home > Net >  Cannot get JavaFx Stage from Node because class com.sun.javafx.stage.EmbeddedWindow cannot be cast t
Cannot get JavaFx Stage from Node because class com.sun.javafx.stage.EmbeddedWindow cannot be cast t

Time:01-11

I am trying to close the current fxml to move to the next one. I followed the reply from this question: close fxml window by code, javafx:

@FXML private javafx.scene.control.Button closeButton;

@FXML
private void closeButtonAction(){
    // get a handle to the stage
    Stage stage = (Stage) closeButton.getScene().getWindow();
    // do what you have to do
    stage.close();
}

And I encountered the same problem as the unanswered comment below it:

Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: com.sun.javafx.stage.EmbeddedWindow cannot be cast to javafx.stage.Stage

All of the other answers also doesn't help. There are little discussion on EmbeddedWindow so I have no clue on what to do next. The previous screen was made with javax.swing, not JavaFx, and the transition is as follow:

import javafx.embed.swing.JFXPanel;

// more code

        JFXPanel fxPanel = new JFXPanel();
        this.add(fxPanel);
        
        this.setTitle("Title");
        this.setSize(1024, 768);
        this.setVisible(true);
        Platform.runLater(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    FXMLLoader loader = new FXMLLoader(getClass().getResource("<String url to my fxml file>"));
                    ScreenController controller = new ScreenController();
                    loader.setController(controller);
                    Parent root = loader.load();
                    fxPanel.setScene(new Scene(root));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

// more code

By the time I'm done writing the context, I think the problem may lie in the usage of JFXPanel, but I can't find a solution either. So helps are appreciated. Thanks!

CodePudding user response:

To close the containing JFrame in a mixed Swing and JavaFX application, from a JavaFX controller, you need to provide the controller with sufficient information to close the window. Probably the best way to decouple this properly is to just have a Runnable in the controller that knows how to close the window:

public class ScreenController {

    private Runnable windowCloser ;

    public void setWindowCloser(Runnable windowCloser) {
        this.windowCloser = windowCloser;
    }

    // ...

    @FXML
    private void closeButtonAction(){
        
        // do what you have to do

        // close the current window:
        windowCloser.run();
    }

    // ...
}

And then:

    JFXPanel fxPanel = new JFXPanel();
    this.add(fxPanel);
    
    this.setTitle("Title");
    this.setSize(1024, 768);
    this.setVisible(true);

    // Assuming this is a JFrame subclass
    // (otherwise replace "this" with a reference to the JFrame):

    Runnable windowCloser = () -> SwingUtilities.invokeLater(
        () -> this.setVisible(false)
    );

    Platform.runLater(() -> {

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("<String url to my fxml file>"));
            ScreenController controller = new ScreenController();

            controller.setWindowCloser(windowCloser);

            loader.setController(controller);
            Parent root = loader.load();
            fxPanel.setScene(new Scene(root));
        } catch (IOException e) {
            e.printStackTrace();
        }
    });

You should also consider just loading the FXML into the current JFXPanel, which is much easier:

public class ScreenController {


    // ...

    @FXML
    private Button closeButton;

    @FXML
    private void closeButtonAction(){

        Parent root = /* load next FXML */ ;
        closeButton.getScene().setRoot(root);
    }

    // ...
}
  • Related