0

Say I have a window, with a button. And everytime that button is pressed I want the current window to be disposed and a new one to be shown.

In Swing, that was easy, but I can't find the syntax for it in JavaFx? So in this case, with my example code, how do I do this?

public class Main extends Application {

    Parent root;
    Scene scene;

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

        scene = new Scene(root);

        primaryStage.setScene(scene);

        primaryStage.sizeToScene();
        primaryStage.setResizable(false);

        primaryStage.show();


        root.setOnMouseClicked((MouseEvent mouseEvent) -> {
            if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
                if (mouseEvent.getClickCount() == 2) {



                        Stage stage = new Stage();
                        stage.setScene(primaryStage.getScene());
                        stage.show();
                        primaryStage.close();


                }
            }
        });
    }


    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
     }

Trying to create a new window: http://sv.tinypic.com/r/1jkq4w/8

FXML:

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.text.*?>

<VBox prefHeight="430.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="blackjack.FXMLDocumentController">
  <children>
    <AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
      <children>
            <Label fx:id="labelPlayerTotal" layoutX="510.0" layoutY="335.0" prefHeight="15.0" prefWidth="121.0" text="Playertotal:" />
            <Label fx:id="labelDealerTotal" layoutX="510.0" layoutY="359.0" prefHeight="15.0" prefWidth="112.0" text="Dealertotal:" />
            <TextArea fx:id="dealerArea" layoutY="29.0" prefHeight="159.0" prefWidth="503.0" />
            <TextArea fx:id="playerArea" layoutY="244.0" prefHeight="159.0" prefWidth="503.0" />
            <Button fx:id="stayButton" layoutX="512.0" layoutY="173.0" mnemonicParsing="false" onAction="#drawCardForDealer" prefHeight="25.0" prefWidth="72.0" text="STAY" />
            <Button fx:id="hitButton" layoutX="512.0" layoutY="130.0" mnemonicParsing="false" onAction="#drawCardForPlayer" prefHeight="25.0" prefWidth="72.0" text="HIT" />
            <Label fx:id="labelWinner" layoutX="104.0" layoutY="208.0" prefHeight="15.0" prefWidth="296.0" />
            <MenuBar fx:id="helpBar">
              <menus>
                <Menu mnemonicParsing="false" text="Help">
                  <items>
                    <MenuItem mnemonicParsing="false" onAction="#aboutApplication" text="About" />
                  </items>
                </Menu>
              </menus>
            </MenuBar>
      </children>
    </AnchorPane>
  </children>
</VBox>
Sishuan Lee
  • 81
  • 1
  • 2
  • 5
  • Is it necessary for you to dispose the window or just disposing the current fxml works for you as well? – ItachiUchiha Feb 24 '15 at 09:44
  • *"..everytime that button is pressed I want the current window to be disposed and a new one to be shown. In Swing, that was easy,.."* Easy maybe, but not recommended. See [The Use of Multiple JFrames, Good/Bad Practice?](http://stackoverflow.com/q/9554636/418556) If Java-FX is limiting the developer to a single 'frame' that has to be something in its favor. – Andrew Thompson Feb 24 '15 at 09:45
  • @AndrewThompson Thank you Andrew, I need this restart button in my JavaFX application, it is very necessary for my application. Is this possible? – Sishuan Lee Feb 24 '15 at 09:53
  • What were you using in Swing to restart the application? – ItachiUchiha Feb 24 '15 at 09:58
  • @ItachiUchiha "this.dispose (to dispose the current window), new Window().setVisible(true);" .. If I remember the syntax correctly. – Sishuan Lee Feb 24 '15 at 10:00
  • Well this doesn't restart your application. It just closes the current Window and creates a new one. Do you want to do the same in JavaFX or restart your complete application? – ItachiUchiha Feb 24 '15 at 10:01
  • @ItachiUchiha Yes Itachi, that is what I want to do. Thank you. – Sishuan Lee Feb 24 '15 at 10:03
  • @ItachiUchiha Do you know how to do it? – Sishuan Lee Feb 24 '15 at 10:38
  • You should not just remove the scene from one stage and add it to the other. Can you post details of what actually you want to achieve from this? – ItachiUchiha Feb 24 '15 at 12:33
  • @ItachiUchiha As you can see, I have a FXML UI. In that UI, let's say that I have a restart button (in this case it's double-click). Everytime that restart button is pressed I want the current window to dissapear, and a new window (the same ui, ofcourse), to be shown. Is this clear? My English is not the best. – Sishuan Lee Feb 24 '15 at 13:41

1 Answers1

0

You can just hide (i.e. dispose) the window by calling hide() or close() on it. And you can just show a new window with exactly the same code you used before:

                primaryStage.close();

                Stage stage = new Stage();

                root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

scene = new Scene(root);

stage.setScene(scene);

stage.sizeToScene();
stage.setResizable(false);

stage.show();

But this seems like way too much for what you want to achieve. Why not just replace the root of the existing scene, and use the existing stage?

try {
    scene.setRoot(FXMLLoader.load(getClass().getResource("FXMLDocument.fxml")));
} catch (Exception exc) {
    exc.printStackTrace();
    throw new RuntimeException(exc);
}

Note though that (either way you do this) you have now replaced the root of the scene; the new root does not have the same mouse handler associated with it. If you use the second method, you can just put the handler on the scene (which doesn't change) instead. Or, perhaps better, is that you can define the listener in the FXML and controller:

<VBox prefHeight="430.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="blackjack.FXMLDocumentController"
fx:id="root"
onMouseClicked="reload">
<!-- ... -->
</VBox>

And the controller:

package blackjack ;

public class FXMLDocumentController {

    // ...

    @FXML
    private VBox root ;

    // ...

    @FXML
    private void reload() throws Exception {

        // Really, it would be way better here to reset the whole UI to its initial
        // state, instead of reloading it from scratch. This should work as a 
        // quick hack though.
        Scene scene = root.getScene();
        scene.setRoot(FXMLLoader.load(Main.class.getResource("FXMLDocument.fmxl")));
    }

    // ...
}
James_D
  • 201,275
  • 16
  • 291
  • 322
  • It worked good. When I double click, the current window is disposed and a new one is displayed. Great! But when I try this again with the new window, the function does not work. Do you know why it only worked the first time? Isn't it possible to just kill everything with System.exit and load a new UI? – Sishuan Lee Feb 24 '15 at 14:28
  • Oh, yes, because the mouse listener is only added to the first root, which is then replaced. I will update. – James_D Feb 24 '15 at 14:35
  • Yes, I agree that resetting the whole UI is better. This is very messy, but thank you anyway. If I would to reset the whole UI, would not System.exit and then load the fxml be sufficient? Or how would I do that? – Sishuan Lee Feb 24 '15 at 15:14
  • I meant "reset all the UI components". (If that is too difficult to code, then probably you need to learn about some design strategies, though that's a much more advanced topic.) The idea is to have less impact on the system, not more. If you call `System.exit(...);`, you will exit the application completely, so anything code after that will not get executed. I think reloading in the controller the way I showed is a reasonable compromise. – James_D Feb 24 '15 at 15:34
  • Ok, thank you. I am suprised by how much work it is for something so small. Swing was much more easier. – Sishuan Lee Feb 24 '15 at 15:37
  • Well, there's basically only two lines of code here to do what you want, plus the `onMousedClicked` attribute. So I don't think that's too complex really. A huge amount of Swing code has threading issues that may or may not manifest themselves at some point; JavaFX does a much better job of creating a structure (`Application.start(...)`) where those errors are less likely, so I think it's better in the long run. – James_D Feb 24 '15 at 15:41
  • I meant by that "A huge amount of code written using Swing has threading issues" (i.e. application code, not the Swing library itself). – James_D Feb 24 '15 at 16:05
  • Well, I just realized that all I can do as a restart is to clear all the fields and labels, and reset the values to 0. I did not need to create a whole new window. So stupid of me. Thanks anyway! :D – Sishuan Lee Feb 24 '15 at 18:30
  • That was what I meant by "reset all the UI components" – James_D Feb 24 '15 at 18:32