0

I've got a small bug in JavaFX and need help. I want to generate a random number within a bound that the user can choose. I chose a slider and get the value in the controller when the user changes it and set it to the bound of the random number. But when I start to check if some user input is higher or lower than this number the bound goes back to 100 (which is the default value when the user doesn't change the slider). Here is some code:

Main:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {
    public static Stage pStage;

    public static Parent root1;
    public static Parent root2;
    public static Parent root3;

    public static Scene scene1;
    public static Scene scene2;
    public static Scene scene3;

    public Main() {
    }

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

        pStage = stage;

        root1 = FXMLLoader.load(getClass().getResource("scene1.fxml"));
        root2 = FXMLLoader.load(getClass().getResource("scene2.fxml"));
        root3 = FXMLLoader.load(getClass().getResource("scene3.fxml"));


        scene1 = new Scene(root1);
        scene2 = new Scene(root2);
        scene3 = new Scene(root3);

        stage.setScene(scene1);
        stage.show();

    }

    public static void main(String[] args) {
        launch(args);
    }
}

Controller:

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;

public class Controller {

    GuessingGame guessingGame = new GuessingGame();
                    //Hier die Zufallszahl hinsetzen und auf 100 und drüben dann mit Setter und Getter abgreifen

    @FXML
    private TextField textfield;
    @FXML
    private Label countText;
    @FXML
    public Label notification;
    @FXML
    public Label textBetween;
    @FXML
    public Slider sliderSettings;

    int currentNumber;

    @FXML
    public void clickedOnExit() {
        System.exit(1);
    }
    @FXML
    public void clickedOnSettings() {
        Main.pStage.setScene(Main.scene3);
        System.out.println(guessingGame.getRandomBound());
    }
    @FXML
    public void sliderSetValue() {
        guessingGame.setRandomBound((int) sliderSettings.getValue());
        System.out.println(guessingGame.getRandomBound());
    }
    @FXML
    public void clickedBackToMenuSettings() {
        Main.pStage.setScene(Main.scene1);
        System.out.println(guessingGame.getRandomBound());
    }
    @FXML
    public void clickedOnPlay() {
        Main.pStage.setScene(Main.scene2);  //Beim wechsel zu szene 2 wird der wert wieder auf 100 gesetzt
        System.out.println(guessingGame.getRandomBound());
    }
    @FXML
    public void clickedBackToMenu() {
        Main.pStage.setScene(Main.scene1);
    }
    @FXML
    public void enteredTextfield() {

        System.out.println(guessingGame.getNumber());

        currentNumber = Integer.parseInt(textfield.getText());

        GuessingGame.Result checkNumber;

        checkNumber = guessingGame.evaluateEnteredNumber(currentNumber);

        if (checkNumber == GuessingGame.Result.HIGHER) {
            notification.setText("HIGHER");
        }
        ;
        if (checkNumber == GuessingGame.Result.LOWER) {
            notification.setText("LOWER");
        }
        ;
        if (checkNumber == GuessingGame.Result.EQUALS) {
            notification.setText("YOU GOT IT!");
            textBetween.setText("Congratulations! The number was: " + guessingGame.getNumber());
        }
        ;
        textfield.clear();
        countText.setText("" + guessingGame.getCounter());  //Gibts ihr eine bessere Lösung?
    }
}

The Game:

import java.util.Random;

public class GuessingGame {

    Random rand = new Random();

    private int number;
    private int counter;
    //Variable die maxhöhe der Zufallszahl am Anfang auf 100 Stand
    private int randomBound = 100;

    public enum Result {
        EQUALS, HIGHER, LOWER
    }

    //Random number muss noch implementiert werden, sodass sie im Bound steht
    public GuessingGame() {
        getNumberToGuess();             //Konstruktor
    }

    public int getNumberToGuess() {
        this.number = rand.nextInt(randomBound);                 //im bound muss der wert vom slide sein
        return number;
    }

    //Methode für das Spielgeschehen gibt Das Ergebnis wieder obs höher/tiefer/gleich ist
    public Result evaluateEnteredNumber(int enteredNumber) {
        Result result;

        counter++;

        if (number > enteredNumber) {
            result = Result.HIGHER;
        } else if (number < enteredNumber) {
            result = Result.LOWER;
        } else {
            result = Result.EQUALS;
        }
        return result;
    }


    //----------------------------------------------------//
    //Getter und Setter//

    //Setter und Getter für die Zufallszahl
    public void setNumber(int  newNumber) {
        this.number = newNumber;
    }
    public int getNumber() {
        return number;
    }
    //Setter und Getter für den Versuchzähler
    public void setCounter(int newCounter) {
        this.counter = newCounter;
    }
    public int getCounter() {
        return counter;
    }
    //Setter und Getter für Die maxhöhe der Zufallszahl
    public void setRandomBound(int newRandomBound) {
        randomBound = newRandomBound;
    }
    public int getRandomBound() {
        return randomBound;
    }
}

Scene 1:

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

        <?import javafx.scene.control.Button?>
        <?import javafx.scene.control.Label?>
        <?import javafx.scene.layout.AnchorPane?>
        <?import javafx.scene.text.Font?>


<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
   <Button fx:id="exitButton" layoutX="505.0" layoutY="349.0" mnemonicParsing="false" onAction="#clickedOnExit" prefHeight="37.0" prefWidth="81.0" text="Exit" />
   <Button fx:id="playButton" layoutX="237.0" layoutY="163.0" mnemonicParsing="false" onAction="#clickedOnPlay" prefHeight="37.0" prefWidth="126.0" text="Play" />
   <Button fx:id="settingsButton" layoutX="237.0" layoutY="213.0" mnemonicParsing="false" onAction="#clickedOnSettings" prefHeight="37.0" prefWidth="126.0" text="Settings" />
   <Label layoutX="66.0" layoutY="14.0" prefHeight="117.0" prefWidth="469.0" text="GUESSING GAME">
      <font>
         <Font name="Arial Black" size="49.0" />
      </font>
   </Label>
</children>
</AnchorPane>

Scene 2

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
   <children>
      <Label layoutX="72.0" prefHeight="20.0" prefWidth="457.0" text="GUESSING GAME">
         <font>
            <Font name="Arial Black" size="48.0" />
         </font>
      </Label>
      <Label layoutX="72.0" layoutY="187.0" text="Your guess:">
         <font>
            <Font name="Arial" size="22.0" />
         </font>
      </Label>
      <Label layoutX="395.0" layoutY="187.0" text="Attempts:">
         <font>
            <Font name="Arial" size="22.0" />
         </font>
      </Label>
      <TextField fx:id="textfield" layoutX="197.0" layoutY="188.0" onAction="#enteredTextfield" prefHeight="25.0" prefWidth="66.0" />
      <Label fx:id="countText" layoutX="496.0" layoutY="188.0" text="0">
         <font>
            <Font name="Arial" size="22.0" />
         </font>
      </Label>
      <Label layoutX="48.0" layoutY="71.0" text="My number is a random number up to 100! Try to guess it!">
         <font>
            <Font name="Arial Black" size="16.0" />
         </font>
      </Label>
      <Label fx:id="notification" layoutX="221.0" layoutY="120.0" text="Type a number!">
         <font>
            <Font name="Arial Black" size="22.0" />
         </font>
      </Label>
      <Label fx:id="textBetween" layoutX="72.0" layoutY="272.0" prefHeight="26.0" prefWidth="356.0" text="Your number is between 0 and 100">
         <font>
            <Font name="Arial Black" size="17.0" />
         </font>
      </Label>
      <Button fx:id="backToMenu" layoutX="485.0" layoutY="361.0" mnemonicParsing="false" onAction="#clickedBackToMenu" text="Back to Menu" />
   </children>
</AnchorPane>

Scene 3:

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
   <children>
      <Slider fx:id="sliderSettings" layoutY="200.0" max="1000.0" minorTickCount="4" onMouseReleased="#sliderSetValue" prefHeight="38.0" prefWidth="592.0" showTickLabels="true" showTickMarks="true" snapToTicks="true" value="100.0" />
      <Label layoutX="4.0" layoutY="117.0" prefHeight="47.0" prefWidth="592.0" text="How High can the number you want to guess be?">
         <font>
            <Font name="Arial Black" size="22.0" />
         </font>
      </Label>
      <Button fx:id="backToMenuSettings" layoutX="497.0" layoutY="361.0" mnemonicParsing="false" onAction="#clickedBackToMenuSettings" text="Back to Menu" />
   </children>
</AnchorPane>

The problem now is: The random Bound number changes when you interact with the Slider but when you click on the Play Button the random bound goes back to 100 and also generates a number to 100... and not the amount the user decided to have (Slider)

Mindmax
  • 49
  • 1
  • 7
  • 2
    If you're asking for help with debugging your code, you should try to post a [mcve]. At least [edit] your question and add the contents of your FXML file. – Abra Feb 01 '20 at 18:45
  • Pardon my ignorance, but if this is a JavaFX application, where is the class that extends `javafx.application.Application`? A minimal, reproducible example should contain code that I can copy, as posted and without the need to change it, then compile and then run. I can't run your example code because it has no `main()` method. – Abra Feb 01 '20 at 19:03
  • Allright I can give you the whole package... you said just the most minimal example. But alrigth it's kind that you want to help me. – Mindmax Feb 01 '20 at 20:44

1 Answers1

0

So add this to your Controller

 @FXML
public void initialize() {
    System.out.println(guessingGame);
}

In your output you will notice this

sample.GuessingGame@29794acb
sample.GuessingGame@6cc12f4f
sample.GuessingGame@757b7ff5

Essentially, since the same controller is configured in the fxml for each of the scenes, each will get its own instance and therefore its own instance of the GuessingGame.

There are a few ways to solve this - my personal recommendation would be to keep your controllers separated since fxml controllers can get out of hand quickly.

Either way, have the GuessingGame initialized outside of the controller and pass it in.

You could, of course, keep the single controller model and pass that into all three scenes. But then you will not be about to configure the actions into the fxml.

Hope this helps.

jayaram S
  • 580
  • 6
  • 13
  • So I have three Controllers and put the initialization method in all of them but where should I initialize the GuessingGame that generates the game and in the end the random number... ps:i'm a noob.... – Mindmax Feb 02 '20 at 10:13
  • 1
    @Mindmax Avoid sharing the same controller class between multiple FXML files. It adds unnecessary complexity and violates [SOLID principles](https://en.wikipedia.org/wiki/SOLID)—specifically [single responsibility](https://en.wikipedia.org/wiki/Single_responsibility_principle). Since you want to share the same `GuessingGame` between different views you need to pass the same instance to each controller. Check out the various answers to [Passing Parameters JavaFX FXML](https://stackoverflow.com/q/14187963/6395627) for some ideas. – Slaw Feb 02 '20 at 12:55
  • I'm still toooo dump and tomorrow is my deadline. can't you tell me exactly what I have to write? Please – Mindmax Feb 02 '20 at 13:53