How to close a new popup window from Controller in JavaFX - javafx

I have Controller.java for Scene.fxml and ControllerSettings.java for WindowSettings.fxml. In Controller.java I create a new popup window (no dialog) with following method:
#FXML
public void handleSubmenuSettings(ActionEvent event) throws IOException {
Stage stage;
Parent root;
ControllerSettings controller;
stage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("WindowSettings.fxml"));
root = (Parent) loader.load();
controller = (ControllerSettings) loader.getController();
stage.setScene(new Scene(root));
stage.setTitle("Settings");
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.initOwner(submenuSettings.getScene().getWindow());
stage.showAndWait();
stage.setOnCloseRequest(e -> {
e.consume();
controller.saveSettings();
stage.close();
});
}
I want to save the settings when closing the new popup window but that doesn't work with stage.setOnCloseRequest.

The showAndWait() method will block execution until the window has closed; i.e. subsequent statements will not be executed until after the window is closed. So you don't register the listener for the close request until after the window has been closed. Clearly, no request to close the window will occur after the window is closed, so your handler is never invoked.
It's not really clear why you are using a close request handler anyway. Presumably you simply want to call controller.saveSettings() after the window closes. Since you are using showAndWait() you can just do:
#FXML
public void handleSubmenuSettings(ActionEvent event) throws IOException {
Stage stage;
Parent root;
ControllerSettings controller;
stage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("WindowSettings.fxml"));
root = (Parent) loader.load();
controller = (ControllerSettings) loader.getController();
stage.setScene(new Scene(root));
stage.setTitle("Settings");
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.initOwner(submenuSettings.getScene().getWindow());
stage.showAndWait();
controller.saveSettings();
}

Related

Opening fxml file for certain time and go back to the main screen?

How do I display an fxml file for some seconds and close that fxml file and return to the mainpage.fxml?
I have tried to add hideThispage method to the initialize method in the controller class of the fxml but I guess the initialize methods just runs before the class is actually loaded so I cannot run this code.
#FXML
public void hideThisPage() throws InterruptedException, IOException {
Window window = new Stage();
PauseTransition pause = new PauseTransition(Duration.seconds(5));
pause.setOnFinished(e -> window.hide());
pause.play();
FxmlDisplay fxmlDisplay = new FxmlDisplay();
fxmlDisplay.stageSelection("View/Main.fxml");
}
To return to the main.fxml or any fxml I have a method that I call:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(path));
Parent root = fxmlLoader.load();
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.show();
In my case, I have a print button in my printreceipt.fxml file that prints the contents. Then it switches to the printpage.fxml ( i am able to switch to the page) But my problem is the printpage.fxml is supposed to be displayed only for 5 seconds and close. then it should go back to main.fxml. how and where do I call the hidethisPage() method?
#FXML
void printRandomTicket(ActionEvent event) throws SQLException, ClassNotFoundException, JRException, IOException, InterruptedException {
FxmlDisplay fxmlDisplay = new FxmlDisplay();
((Node) event.getSource()).getScene().getWindow().hide();
fxmlDisplay.stageSelection("/View/Dialogs/PrintingTicket.fxml");
GenerateTicket generateTicket = new GenerateTicket();
generateTicket.generateTicket();
PrintTicket printTicket = new PrintTicket();
printTicket.printTicket();
}
I hope this clarifies it.

JavaFX Changing Stage/Scene without reset values in the previous windows

I got an Application or a screen where I can send E-Mails. I also got a template screen as a whole new window. For e.g. I already write 3 email addresses in the TO TextField. I want them to stay, even if I change the whole stage because when I then go to the TemplatePicker Screen and pick a template, the initialize will be called again in the EmailController and all recipicients in the TextField are gone.
Code E-Mail:
public void buttonPickTemplate(ActionEvent event) throws IOException {
Main.fxmlval.add("/application/controller/MailController/SendMail.fxml");
FXMLLoader loader = new FXMLLoader(getClass().getResource("/application/controller/TemplateController/TemplateAuswahlFenster.fxml"));
Parent parent = loader.load();
TemplateController templateController = loader.<TemplateController>getController();
templateController.setEmailVariablen(empfaengerField.getText(), ccField.getText(), bccField.getText(), betreffField.getText());
Scene homeScreenScene = new Scene(parent);
Stage window = (Stage) ((Node) event.getSource()).getScene().getWindow();
window.setScene(homeScreenScene);
}
As you can see I tried to give the variables with a setter to the next screen and set them then back, but that would be horrible. Normally the method to change a screen always looks like this, if you have to throw no variables:
Parent detailsScreen = FXMLLoader.load(getClass().getResource("/application/controller/DetailsController/Details.fxml"));
Scene detailsScene = new Scene(detailsScreen);
Stage window = (Stage) ((Node) event.getSource()).getScene().getWindow();
window.setScene(detailsScene);
So and this methode in the TemplateController calls again the EmailController and FXML:
public void auswaehlen(ActionEvent event)throws IOException
{
FXMLLoader loader = new FXMLLoader(getClass().getResource("../MailController/SendMail.fxml"));
Parent homeScreen = loader.load();
MailSender wpc=loader.<MailSender>getController();
wpc.setTemplate(this.settemplate.getDatei());
Scene homeScreenScene = new Scene(homeScreen);
Stage window = (Stage) ((Node) event.getSource()).getScene().getWindow();
window.setScene(homeScreenScene);
}

Switching scenes in JavaFX with ActionEvent

Hello I am having an JavaFX app with few controllers and I have 2 options to get back to previous screen. User can click button 'leave' or after finishing some tasks on this screen will be moved to previous automatically. I have problem here because I've created method wiut fxml annotation which takes ActionEvent object as parameter and is called when user click button and when user will finish tasks and should be moved automatically to previous screen I cannot call this method because I dont this object, it's created when an action - click in this case is made. How can I make it possible for both 'exit' options?
So here is my method which is used 'onAction' for my button:
#FXML
private void leaveRoomAction(ActionEvent event) {
try {
removePlayerFromRoom();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("LobbyView.fxml"));
Parent root = (Parent) loader.load();
LobbyController lobbyController = (LobbyController)loader.getController();
lobbyController.setClientThread(client);
lobbyController.setNameAndBalance(client.getPlayer().getName());
Scene scene = new Scene(root);
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
And later in other part of programe:
if(isFinished()){
//here I want write leaving this screen and getting back to previous
}
First, find another way to get a reference to the Stage. Since you almost certainly have a reference to some node in the scene in your controller, you can replace
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
with
Stage stage = (Stage) anyNode.getScene().getWindow();
where anyNode is just something you have injected into the controller.
Now you don't need the parameter at all, so you can just remove it. I.e. you end up with
#FXML
private Node anyNode ; // probably a more specific type than Node.
#FXML
private void leaveRoomAction() {
try {
removePlayerFromRoom();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("LobbyView.fxml"));
Parent root = (Parent) loader.load();
LobbyController lobbyController = (LobbyController)loader.getController();
lobbyController.setClientThread(client);
lobbyController.setNameAndBalance(client.getPlayer().getName());
Scene scene = new Scene(root);
Stage stage = anyNode.getScene().getWindow();
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
And now you can just call the method:
if ( isFinished() ) {
leaveRoomAction()
}

JavaFX how to close stage to act the same way the 'x' button in the window

I have a controller that opens a new stage as a popup:
#FXML
private void onClickPayments(ActionEvent event) throws IOException{
FXMLLoader loader = new FXMLLoader(getClass().getResource("ClientPayments.fxml"));
Parent root = (Parent) loader.load();
ClientPaymentsController controller = (ClientPaymentsController) loader.getController();
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setScene(scene);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.setOnCloseRequest((WindowEvent we) -> {
clientBLL.retrieve(clientID);
updateWarning();
});
stage.show();
controller.setClientID(clientID);
}
When the other stage is closed by the 'x' button the 'stage.setOnCloseRequest' is executed. But in that stage I have a button to close:
#FXML
private void onClickExit(ActionEvent event){
((Stage) ((Node) event.getSource()).getScene().getWindow()).close();
}
It closes, but the method 'stage.setOnCloseRequest' isn't being executed.
Is this method wrong or is there a way to close a popup in a way that acts exactly like the 'x' button in the window?
The setOnCloseRequest handler is executed when there is an external request to close the window (i.e. not one from your code). See the documentation.
If it's enough to execute that logic immediately after the window is closed, just use the regular onHidden handler instead:
stage.setOnHidden((WindowEvent we) -> {
clientBLL.retrieve(clientID);
updateWarning();
});
If you really need to use the onCloseRequest handler (e.g. because you might want to veto the close), just move your close logic to a method and invoke it from both types of request to close the window.
public void doClose() {
clientBLL.retrieve(clientID);
updateWarning();
}
#FXML
private void onClickExit(ActionEvent event){
doClose();
((Node) event.getSource()).getScene().getWindow().hide();
}
and
stage.setOnCloseRequest((WindowEvent we) -> {
controller.doClose();
});

JavaFX + Scene Builder how switch scene

I'm working with JavaFx and Scenebuilder and want create a local app for myself called "Taskplanner" in eclipse.
I created a new Stage and set it with a Scene (see Main.java). But not sure how to set a new Scene in the old stage (see Controller.java). Didnt also not find out if it is possible pass the signInButtonClicked()-Methode the "Stage primaryStage" over Scene Builder
Can anybody help ?
Controller.java:
#FXML
Button btnSignIn;
#FXML
public void signInButtonClicked() throws Exception
{
//Here I want call the new Scene(SignInGUI.fxml) in my old Stage
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../view/SignInGUI.fxml"));
}
Main.java:
#Override
public void start(Stage primaryStage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("../view/LoginGUI.fxml"));
primaryStage.setTitle("Taskplanner");
primaryStage.setScene(new Scene(root,500,500));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
You can get a reference to the Scene and Window from your button reference. From there, it's up to you to decide how to you want to show the new view.
Here's how you get those references:
Scene scene = btnSignIn.getScene();
Window window = scene.getWindow();
Stage stage = (Stage) window;
You can change the view by changing the root of your Scene:
FXMLLoader loader = ... // create and load() view
btnSignIn.getScene().setRoot(loader.getRoot());
Or you can change the entire Scene:
FXMLLoader loader = ... // create and load() view
Stage stage = (Stage) btnSignIn.getScene().getWindow();
Scene scene = new Scene(loader.getRoot());
stage.setScene(scene);

Resources