0

I am about to finish my very first JavaFX application, which is not much more than a simple calculation tool with a GUI. The program does the following:

  • print two random generated integers
  • let me insert the fraction of those two numbers
  • print statement whether my insertet answer was correct or not

However, i didn't manage to figure out how to implement a "Reset" or "Restart"-Button in order to avoid closing the programm each time.

This is my code:

package sample;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;


import java.io.InputStream;

public class Game extends Application implements EventHandler<ActionEvent> {

    private Button button;

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Pot Odds Trainer");

        Class<?> genericClass = this.getClass();
        InputStream input1 = genericClass.getResourceAsStream("img/chipsGREEN.png");
        InputStream input2 = genericClass.getResourceAsStream("img/chipsREDsmall.png");
        InputStream input3 = genericClass.getResourceAsStream("img/01ACE.png");
        InputStream input4 = genericClass.getResourceAsStream("img/01ACE.png");
        InputStream input5 = genericClass.getResourceAsStream("img/chipsBLUE03small.png");
        InputStream input6 = genericClass.getResourceAsStream("img/chipsGREENstack.png");

        Image image1 = new Image(input1);
        ImageView imageView1 = new ImageView(image1);
        Image image2 = new Image(input2);
        ImageView redChips = new ImageView(image2);
        Image image3 = new Image(input3);
        ImageView imageView3 = new ImageView(image3);
        Image image4 = new Image(input4);
        ImageView imageView4 = new ImageView(image4);
        Image image5 = new Image(input5);
        ImageView blueChipsStack = new ImageView(image5);
        Image image6 = new Image(input6);
        ImageView greenChipStack = new ImageView(image6);

        Button buttonRotate = new Button("Rotate");
        buttonRotate.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                double value = imageView1.getRotate();
                imageView1.setRotate(value + 30);
            }
        });

        button = new Button("Text of Button");

        Button buttonRestart = new Button("Restart");
        buttonRestart.setOnAction((ActionEvent event) -> {
            ((Node) (event.getSource())).getScene().getWindow().hide();
        });

        button.setOnAction(this);

        GridPane gridPane = new GridPane();
        gridPane.setHgap(10);
        gridPane.setVgap(10);
        gridPane.setGridLinesVisible(false);

        int potSizeValue = Potsize.getPotSize();
        int betSizeValue = Potsize.getBetSize();
        int stackSizeValue = Potsize.getStackSize();

        Potsize potsize = new Potsize(potSizeValue);
        Potsize betsize = new Potsize(betSizeValue);
        Potsize stacksize = new Potsize(stackSizeValue);

        Label potsizeText = new Label("Der Pot liegt bei: ");
        Label betsizeText = new Label("Ein Call beträgt: ");
        Label stacksizeText = new Label("Dein Stack liegt bei: ");

        Label potOddsLabel = new Label("Pot Odds:");
        Label textConfirm = new Label();

        Button submitButton = new Button("Submit");
        TextField potOddsTextField = new TextField();
        potOddsTextField.setMaxWidth(50);
        submitButton.setOnAction(e ->
                {
                    textConfirm.setText(MyMath.checkOdds(potOddsTextField.getText(), (double) betSizeValue / (potSizeValue + betSizeValue)));
                }
        );

        Label potsizeLabel = new Label(potsize.toString());
        Label stacksizeLabel = new Label(stacksize.toString());
        Label betsizeLabel = new Label(betsize.toString());

        gridPane.add(button, 0, 0, 1, 1);
        gridPane.add(buttonRotate, 2, 3, 1, 1);
        gridPane.add(imageView1, 0, 2, 1, 1);
        gridPane.add(imageView3, 4, 3, 1, 1);
        gridPane.add(imageView4, 5, 3, 1, 1);
        gridPane.add(potsizeText, 4, 5, 2, 1);
        gridPane.add(betsizeText, 4, 6, 2, 1);
        gridPane.add(stacksizeText, 4, 7, 2, 1);
        gridPane.add(potsizeLabel, 6, 5, 2, 1);
        gridPane.add(betsizeLabel, 6, 6, 2, 1);
        gridPane.add(stacksizeLabel, 6, 7, 2, 1);
        gridPane.add(blueChipsStack, 8, 5, 1, 1);
        gridPane.add(redChips, 8, 6, 1, 1);
        gridPane.add(greenChipStack, 8, 7, 1, 1);
        gridPane.add(potOddsLabel, 4, 8, 2, 1);
        gridPane.add(potOddsTextField, 6, 8, 2, 1);
        gridPane.add(submitButton, 8, 8, 1, 1);
        gridPane.add(textConfirm, 4, 9, 2, 1);
        gridPane.add(buttonRestart, 4, 11, 2, 1);


        Scene scene = new Scene(gridPane, 650, 550);
        scene.getStylesheets().add(Main.class.getResource("css/styles.css").toExternalForm());

        primaryStage.setScene(scene);
        primaryStage.show();

    }

    @Override
    public void handle(ActionEvent event) {
        if (event.getSource() == button) {
            System.out.println("Ooooooo test");

        }
    }


}
This is my Main Class:

package sample;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import java.io.InputStream;
import java.util.concurrent.ThreadLocalRandom;

public class Main {
    public static void main(String[] args) {

        Game game = new Game();
        game.launch(Game.class, args);

    }
}
package sample;

import java.util.concurrent.ThreadLocalRandom;

public class Potsize {

    private int size;

    public Potsize(int size){
        this.size = size;
    }

    static public int getStackSize(){
        return (int)MyMath.round(ThreadLocalRandom.current().nextInt(100, 2500 + 1));
    }

    static public int getPotSize(){
        return (int)MyMath.round(ThreadLocalRandom.current().nextInt(100, 1000 + 1));
    }

    static public int getBetSize(){
        return (int)MyMath.round(MyMath.divide(getPotSize(),  ThreadLocalRandom.current().nextInt(2, 10 + 1)));
    }

    public void setPotSize(int size){
        this.size = size;
    }

    public void setBetSize(int size){
        this.size = size;
    }

    public void setStackSize(int size){
        this.size = size;
    }

    public String toString() {
        return ""+ size;
    }

}

I've read a lot of similar questions but unfortunately, none have helped me so far.

Currently i am having an ActionEvent on "buttonRestart" that closes my programm - however, that's not what i want. I'd like the Scene to simply reset/restart in order to have a "next try".

Can anyone help me?

Thanks so much!

Zest
  • 127
  • 1
  • 7
  • After constructing your scene have an "init' method, that initializes all components to their start values. Invoke this method before `primaryStage.show();` and again when `buttonRestart` is pressed. For more help post [mre] – c0der Jul 14 '19 at 05:25
  • hello c0der, thanks for your help. How does my init() method has to look like? I feel a bit lost. – Zest Jul 14 '19 at 09:34
  • Unrelated note: You shouldn't create an instance of `Game` to invoke the `static` method `Application.launch`. That instance is never used and only the constructor runs and that instance is never used again. `launch` creates it's own instance of the application class. For this reason you should use `Application.launch(Game.class, args);`. (In general it's preferred to use `ClassName.memberName` to refer to a `static` member, since this clearly indicates that a `static` method is used (unless you're violating naming conventions).) – fabian Jul 14 '19 at 09:43

3 Answers3

2

There is no general way of doing this easily: The code could e.g. in some circumstances invoke Platform.exit and at that time it's not possible to prevent the GUI from shutting down.

Depending on the code in some cases passing a stage to the start method may work:

start(primaryStage);

or

primaryStage.hide();
start(new Stage());

But in general I recommend resetting the things changed in the scene to their original state:

private Label potsizeLabel;
private Label stacksizeLabel;
private Label betsizeLabel;

private void initPot() {
    int potSizeValue = Potsize.getPotSize();
    int betSizeValue = Potsize.getBetSize();
    int stackSizeValue = Potsize.getStackSize();

    Potsize potsize = new Potsize(potSizeValue);
    Potsize betsize = new Potsize(betSizeValue);
    Potsize stacksize = new Potsize(stackSizeValue);

    potsizeLabel.setText(potsize.toString());
    stacksizeLabel.setText(stacksize.toString());
    betsizeLabel.setText(betsize.toString());
}

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

    buttonRestart.setOnAction((ActionEvent event) -> {
        // change node properites that could have been modified to their's original states
        imageView1.setRotate(0);
        textConfirm.setText("");

        // redo Potsize thing
        initPot();
    });

    ...

    potsizeLabel = new Label();
    stacksizeLabel = new Label();
    betsizeLabel = new Label();

    initPot();

    ...

}

If the Potsize class contains a state in a static member, you also need to reset this (but it would be better to avoid this scenario in the first place; note that this could also prevent the first approaches from working properly).


I'm not sure about the responsibility of the Potsize class, but it's sole purpose (ignoring static members) currently seems to be to convert an int to a String which does not require creating an instance of that class; Integer.toString(potSizeValue) can be used, if the int is converted to a string containing it's decimal representation; otherwise a static method seems sufficient.

fabian
  • 80,457
  • 12
  • 86
  • 114
  • hello fabian, i think i managed to solve it with your help. i am so grateful! thank you so much for your detailed answer and helpful insight. – Zest Jul 14 '19 at 17:46
1

I dont see your Potsize class but I think you have to reset this values

int potSizeValue = Potsize.getPotSize();
int betSizeValue = Potsize.getBetSize();
int stackSizeValue = Potsize.getStackSize();

Potsize potsize = new Potsize(potSizeValue);
Potsize betsize = new Potsize(betSizeValue);
Potsize stacksize = new Potsize(stackSizeValue);

And then refresh on GridPane

gridPane.add(potsizeLabel, 6, 5, 2, 1);
gridPane.add(betsizeLabel, 6, 6, 2, 1);
gridPane.add(stacksizeLabel, 6, 7, 2, 1);
0

The first two links provide StackOverflow source code posts on implementing refresh options for scenes. The last link concerns JavaFX multithreading from Oracle’s tutorials, an option you will likely need to consider if you don’t want to completely close your JavaFX application just to refresh a scene.

Restarting your application on-click. How to restart a JavaFX application when a button is clicked

Reloading JavaFX application How to reload an Application in JavaFX?

There might not be a quick solution to reloading a scene if your scene is in the main thread that contains your main JavaFX application. You should create a new thread and place the scene within this thread, stop the same thread update the scene as needed, and then launch a new thread with the updated scene. Here’s a link to concurrency (multithreading) with JavaFX.

Concurrency in JavaFX https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm

P.S. By the way, a couple of months ago I built a couple of JavaFX gui applications to take user file information and process the file. I, too, wanted to leave the application open but couldn’t and found the Oracle resources.

ManLaw
  • 115
  • 1
  • 10
  • thank you. i've visited those links numerous times but they didn't help me. is it really that hard to make a simple "restart" button? – Zest Jul 14 '19 at 10:20