How to restart a JavaFX application when a button is clicked
Asked Answered
C

2

11

I went through almost every post here regarding the matter but most of them doesn't explain what to do properly. To the question:

I created a javaFX application, a dice game, human player vs. computer, but during any time while playing the game human player should be able to click button "new game" and what it should do is to restart the game from beginning.

I tried relaunching the stage again but in javafx we cannot call the launch method twice.

1)Is there a way i can implement this without restarting the whole application?

2)if not how can i restart the application completely using a button click?

Main class

public class Main {
public static void main(String[] args) {
    GameUI gameUI = new GameUI();

    gameUI.launch(GameUI.class, args);

}   

GameUI (i removed many codes from this class to make it short. codes that i think enough to give an idea is included. sorry if it is too long.)

public class GameUI extends Application  {

 //all btn and label declarations 
//creating instances for necessary classes

private Scene scene;

@Override
public void start(Stage primaryStage) throws Exception {

    //Displaying Dice for Player and Computer
    setLabelsPlyr(diesP);
    setLabels(diesC);

    btnThrow = new Button("Throw");
    btnThrow.setPrefSize(70, 40);

    //Throw action is performed
    btnThrow.setOnAction(e -> {

    //setting and displaying dies
      DieClass[] com = getNewDiceArrC();  
      lblDiceOneC.setGraphic(new ImageView(diesC[0].getDieImageC()));
      //so on.....

      DieClass[] playerAr = getNewDiceArrP();
      lblDiceOnePlyr.setGraphic(new ImageView(diesP[0].getDieImageP()));
      //so on...
    });

    btnNewGame = new Button("New Game");
    btnNewGame.setOnAction(e -> {

           **//WHAT TO DO HERE?????**

    });

    //setting layouts


    GridPane gridPane = new GridPane();
    gridPane.add(lblComputer, 0, 0);
    //so on.....

    Scene scene = new Scene(gridPane, 1100, 400);
    primaryStage.setScene(scene);
    primaryStage.setTitle("dice Game");
    primaryStage.show();

}

//some other methods
public void setLabels(DieClass[] dies) {
    for (int i=0; i < dies.length; i++) {
        lblDiceOneC = new Label();
        lblDiceOneC.setGraphic(new ImageView(dies[0].getDieImageC()));
        ++i;
       //so on.....

        break;
    }
}

public void setLabelsPlyr(DieClass[] dies){
    for (int i=0; i<dies.length; i++) {
        lblDiceOnePlyr = new Label();
        lblDiceOnePlyr.setGraphic(new ImageView(dies[0].getDieImageP()));
        ++i;
        lblDiceTwoPlyr = new Label();
        //so on......
        break;
    }
}

p.s I am very new to JavaFX and somewhat new to java programming.

Colostrum answered 14/1, 2016 at 11:6 Comment(0)
C
9

You already noticed that you cannot do the launching process again. Therefore your best option is to rewrite the application class and move the initialisation logic to a new method:

void cleanup() {
    // stop animations reset model ect.
}

void startGame(Stage stage) {
    // initialisation from start method goes here

    btnNewGame.setOnAction(e -> {
       restart(stage);
    });

    stage.show();
}

void restart(Stage stage) {
    cleanup();
    startGame(stage);
}

@Override
public void start(Stage primaryStage) {
    startGame(primaryStage);
}

Notes

  • Depending on the parts of the scene changed, it may be enough to change the state of some of the nodes (more efficient than creating a new scene). (Just take a look at the changes you made during the game and decide for yourself)
  • launch() is a static method and you should not create a instance of your application class yourself for that reason. Use Application.launch(GameUI.class, args); instead and let the method handle the creation of the GameUI instance.
  • It may be a better design to move the UI creation to a class different to the application class. This way reuse of the code is easier, since it does not require the creation of a instance of a subclass of Application.
Clermontferrand answered 14/1, 2016 at 13:18 Comment(2)
Thanks for the elaborated answer, about moving UI creation to a different class, i tried it but when i do that i cannot update the UI i.e dies get changed(within the program) but it does not get updated in the UI. i researched and as far as i understood it is because application runs as a thread and we cannot update while thread is running. i would certainly like to move ui parts to another class but couldn't do that.Colostrum
@RaveenAthapaththu:There are ways to call code from the application thread (E.g.Platform.runLater).But there really isn't much difference, if you move some code to another class.E.g. you could write a factory that creates the scene and all you'd do in the start method is put the scene in the Stage and show it.Of course you have to be careful because of the application lifecycle/different threads, but IMHO it's worth it.Maybe you should start with the original version and refractor using the delegation pattern (with constructor, start [, init?]) and then refractor the code step by step.Clermontferrand
L
0

In your Start() function, add the following line:

Platform.setImplicitExit(false);

This will make your application run in background without exiting.

Now, use a wrapper function to start the second time, say:

void displayApplication() {
         Platform.runLater(new Runnable() {
            @Override
            public void run() {
                try {
                    start(new Stage());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
Lardaceous answered 23/9, 2021 at 12:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.