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);
}
// ...
}