JavaFX - Need a for loop to pause and wait for button input

My questions has been answered and my problems solved. I've updated this thread with my final solution

I'm working on this school assignment (quiz program) which we were initially only required to do as a pure text-based console game, but I wanted to challenge myself and try to create it in JavaFX which we have barely begun learning about.

It's a turn-based quiz game, where the player will be presented with a question which s/he will be required to answer either True/False to through two buttons (True or False buttons)

Game flow:

I'm running a for-loop which continues as long as there are questions left in my ArrayList.

The ideal flow would go like this:

0) Enter names and press: Start Game button 1) Present question to player 1. 2) Receive an input through either the True button or the False button. 3) Compare the input with the correct answer pulled from the array. 4) If correct, user gets 1 point - If false, continue to player 2. 5) Change to player two and start over again until no more questions in the ArrayList.

What's working I've got my loop to "function correctly" in the sense that it changes player and continues until there are no more questions in the ArrayList.

Problem I want the for loop to wait for user input through the true/false buttons. However, the for loop runs the entire program without waiting for input.

Question Is it possible to "pause" a for loop and have it wait for an input from one of two buttons? Are there other ways you'd recommend I'd handle this problem?

I'd be super happy if you'd be willing to direct on solving this. Whether through this forum or by sending me a link to further reading is ok. I just can't seem to find a solution by googling it or searching this forum.

The code is filled with System.out.println() for me to see how far the program runs. Please look away from this.

Also... Any suggestions on how I could improve the code would be highly appreciated. Only 8 weeks into Java programming and would love to learn how to do things smarter.

The Main code

package sample;
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 {

@Override
public void start(Stage primaryStage) throws Exception{
    Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
    primaryStage.setTitle("Expert Quiz Game");
    primaryStage.setScene(new Scene(root, 800, 600));
    primaryStage.show();
}


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

The Controller code

package sample;

import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.text.Text;
import java.util.Random;

public class Controller {
@FXML
TextField player1;
@FXML
TextField player2;
@FXML
Text score1;
@FXML
Text score2;
@FXML
Text questionText;
@FXML
Text questionsLeft;
@FXML
Text gameStatus;
@FXML
Button startGame;
@FXML
Button buttonTrue;
@FXML
Button buttonFalse;
//@FXML
//Button nextRound;

@FXML
private void handleStartGame(ActionEvent event) {

    // ******* DECLARE VARIABLES ********

    String playerOneName = player1.getText(); //Saves the name for later use
    String playerTwoName = player2.getText(); //Saves the name for later use
    int playerOneScore = 0;
    int playerTwoScore = 0;
    Random randomQuestionNumber1 = new Random();
    //Random randomQuestionNumber2 = new Random();

    System.out.println(playerOneName + " TEST"); //To TEST if the name is saved
    System.out.println(playerTwoName + " TEST"); //To TEST if the name is saved

    // ******* DECLARE QUESTION ARRAY ********

    ArrayList<String> questionsArray = new ArrayList<String>();
    questionsArray.add("Question 1");
    questionsArray.add("Question 2");
    questionsArray.add("Question 3");
    questionsArray.add("Question 4");
    questionsArray.add("Question 5");
    questionsArray.add("Question 6");

    // ******* DECLARE ANSWER ARRAY ********

    ArrayList<String> answerArray = new ArrayList<String>();
    answerArray.add("True");
    answerArray.add("True");
    answerArray.add("False");
    answerArray.add("True");
    answerArray.add("False");
    answerArray.add("True");

    //int randomQuestionA = randomQuestionNumber1.nextInt(questionsArray.size()); //+0
    //int randomQuestionB = randomQuestionNumber2.nextInt(questionsArray.size()); //+0

    //Button clickedButton = (Button) event.getTarget();
    //String buttonLabel = clickedButton.getText();
    int player = 1;

    for (int i = 0; i < questionsArray.size(); i++) {

        if (player == 1) {

            int randomQuestionA = randomQuestionNumber1.nextInt(questionsArray.size());

            // ****** RETRIEVE AND PRESENT FIRST QUESTION ******

            System.out.println("1. Player: " + playerOneName); // WRITE TO CONSOLE THE CURRENT PLAYER * CAN BE REMOVED
            questionText.setText("Question: " + questionsArray.get(randomQuestionA)); // PRINTS QUESTION TO THE UI
            System.out.println("2. "+questionsArray.get(randomQuestionA)); // WRITES TO CONSOLE THE QUESTION * CAN BE REMOVED

            // ****** GET ANSWER FOR THE QUESTION ******

            String answerFromArray = answerArray.get(randomQuestionA); // TAKES THE ANSWER FROM THE ARRAY AND SAVES AS A NEW STRING
            System.out.println("3." + answerArray.get(randomQuestionA)); // WRITES THE ANSWER FROM THE ARRAY TO CONSOLE * CAN BE REMOVED

            // ****** TEST IF ANSWER IS TRUE ******

            String buttonTrueText = buttonTrue.getText(); // SAVES THE BUTTON TEXT AS A STRING FOR LATER COMPARISON
            String buttonFalseText = buttonFalse.getText(); // SAVES THE BUTTON TEXT AS A STRING FOR LATER COMPARISON

            // ****** IF TRUE, THEN COUNT ONE UP IN SCORE ******

            buttonTrue.setOnAction(e -> {
                System.out.println("4. Now running"); // WRITES TO CONSOLE * CAN BE REMOVED

                String buttonAnswer = " ";              // INITIALIZES THE VARIABLE WITH AN EMPTY STRING
                handleButtonAnswer(event);
                /**if (buttonText.equals("True")) {            // REGISTERS THE BUTTON PRESSED AND SAVES IT IN A VARIABLE
                    buttonAnswer = "True";
                } else if (buttonText.equals("False")) {    // REGISTERS THE BUTTON PRESSED AND SAVES IT IN A VARIABLE
                    buttonAnswer = "False";
                }**/
                if (buttonAnswer == "True" || buttonAnswer == "False") {
                    System.out.println("5. Test");
                }


                System.out.println("6. "+buttonAnswer);
                if (answerFromArray.equals(buttonAnswer)) {
                    System.out.println("7. Answer was correct - Need to count one up in score");//
                }

                score1.setText("Points: " + playerOneScore+1);
                System.out.println("8. "+playerOneScore+1);
                questionsArray.remove(randomQuestionA); // REMOVES QUESTION FROM ARRAYLIST
                answerArray.remove(randomQuestionA); // REMOVES ANSWER FROM ARRAYLIST

                int remainingQuestions = questionsArray.size();
                questionsLeft.setText(remainingQuestions + " questions left");
            });

            // ****** REMOVE THAT QUESTION + ANSWER FROM THE ARRAY  ******

            // ****** CHANGE PLAYER AND START AGAIN  ******



                player = 2;
            System.out.println("Changing to player " +player);
        } else if (player == 2) {
            //clickedButton.setText("O");

            int randomQuestionA = randomQuestionNumber1.nextInt(questionsArray.size());

            // ****** RETRIEVE AND PRESENT FIRST QUESTION ******

            System.out.println("1. Player: " + playerOneName); // WRITE TO CONSOLE THE CURRENT PLAYER * CAN BE REMOVED
            questionText.setText("Question: " + questionsArray.get(randomQuestionA)); // PRINTS QUESTION TO THE UI
            System.out.println("2. "+questionsArray.get(randomQuestionA)); // WRITES TO CONSOLE THE QUESTION * CAN BE REMOVED

            // ****** GET ANSWER FOR THE QUESTION ******

            String answerFromArray = answerArray.get(randomQuestionA); // TAKES THE ANSWER FROM THE ARRAY AND SAVES AS A NEW STRING
            System.out.println("3." + answerArray.get(randomQuestionA)); // WRITES THE ANSWER FROM THE ARRAY TO CONSOLE * CAN BE REMOVED

            // ****** TEST IF ANSWER IS TRUE ******

            String buttonTrueText = buttonTrue.getText(); // SAVES THE BUTTON TEXT AS A STRING FOR LATER COMPARISON
            String buttonFalseText = buttonFalse.getText(); // SAVES THE BUTTON TEXT AS A STRING FOR LATER COMPARISON

            // ****** IF TRUE, THEN COUNT ONE UP IN SCORE ******

            buttonTrue.setOnAction(e -> {
                System.out.println("4. Now running"); // WRITES TO CONSOLE * CAN BE REMOVED

                String buttonAnswer = " ";              // INITIALIZES THE VARIABLE WITH AN EMPTY STRING
                handleButtonAnswer(event);
                /**if (buttonText.equals("True")) {            // REGISTERS THE BUTTON PRESSED AND SAVES IT IN A VARIABLE
                 buttonAnswer = "True";
                 } else if (buttonText.equals("False")) {    // REGISTERS THE BUTTON PRESSED AND SAVES IT IN A VARIABLE
                 buttonAnswer = "False";
                 }**/
                if (buttonAnswer == "True" || buttonAnswer == "False") {
                    System.out.println("5. Test");
                }


                System.out.println("6. "+buttonAnswer);
                if (answerFromArray.equals(buttonAnswer)) {
                    System.out.println("7. Answer was correct - Need to count one up in score");//
                }

                score1.setText("Points: " + playerOneScore+1);
                System.out.println("8. "+playerOneScore+1);
                questionsArray.remove(randomQuestionA); // REMOVES QUESTION FROM ARRAYLIST
                answerArray.remove(randomQuestionA); // REMOVES ANSWER FROM ARRAYLIST

                int remainingQuestions = questionsArray.size();
                questionsLeft.setText(remainingQuestions + " questions left");
            });

            // ****** REMOVE THAT QUESTION + ANSWER FROM THE ARRAY  ******

            // ****** CHANGE PLAYER AND START AGAIN  ******

            player = 1;
            System.out.println("Changing to player " +player);

        }
    }
}
@FXML
private String handleButtonAnswer(ActionEvent event) {
    String buttonAnswer = "";
    // (1)
    Button b = (Button) event.getSource();
    // (2)
    String t = b.getText();

    System.out.println("4. the text on the button was: "+t);

    if (t.equals("True")){
        buttonAnswer = "True";  // demo
    }else if (t.equals("False")){
        buttonAnswer = "False";
    }
    return buttonAnswer;
}

}

The fxml code

Design is not done - Need it to work before styling it properly

<?xml version="1.0" encoding="UTF-8"?><?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="794.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
    <Label layoutX="225.0" layoutY="47.0" prefHeight="66.0" prefWidth="334.0" text="Java ExpertQuiz" textAlignment="CENTER">
        <font>
            <Font name="Cambria Bold" size="45.0" />
        </font>
    </Label>
    <TextField fx:id="player1" layoutX="79.0" layoutY="154.0" prefHeight="39.0" prefWidth="201.0" promptText="Enter name for player1" />
    <TextField fx:id="player2" layoutX="503.0" layoutY="154.0" prefHeight="39.0" prefWidth="222.0" promptText="Enter name for player2" />
    <Text fx:id="score1" layoutX="79.0" layoutY="232.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Ponits" />
    <Text fx:id="score2" layoutX="503.0" layoutY="232.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Points" />
    <Text fx:id="questionText" layoutX="38.0" layoutY="315.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Question" textAlignment="CENTER" wrappingWidth="717.1240234375">
        <font>
            <Font size="38.0" />
        </font>
    </Text>
    <Button fx:id="startGame" layoutX="318.0" layoutY="154.0" mnemonicParsing="false" onAction="#handleStartGame" text="Start game" />

    <Text fx:id="questionsLeft" layoutX="301.0" layoutY="505.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Questions left: " textAlignment="CENTER" wrappingWidth="191.9072265625" />
    <Text fx:id="gameStatus" layoutX="320.0" layoutY="547.0" strokeType="OUTSIDE" strokeWidth="0.0" text="The winner is:" />
    <Button fx:id="buttonTrue" layoutX="150.0" layoutY="390.0" mnemonicParsing="false" onAction="#handleButtonAnswer" text="True" />
    <Button fx:id="buttonFalse" layoutX="582.0" layoutY="390.0" mnemonicParsing="false" onAction="#handleButtonAnswer" text="False" />

</children>
</AnchorPane>

EVERYTHING IS WORKING - HERE'S MY FINAL SOLUTION

package sample;

import java.net.URL;
import java.util.*;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.text.Text;

public class Controller {
@FXML
TextField player1;
@FXML
TextField player2;
@FXML
Text score1;
@FXML
Text score2;
@FXML
Text statusText;
@FXML
Text questionsLeft;
@FXML
Text currentPlayer;
@FXML
Button startGame;
@FXML
Button buttonTrue;
@FXML
Button buttonFalse;
@FXML
Button nextRound;

private ArrayList<String> questionsArray = new ArrayList<String>();

private ArrayList<String> answerArray = new ArrayList<String>();

private int player = 0;

private int remainingQuestions = 0;

private int playerOneScore;

private int playerTwoScore;

private String playerOneName = "";

private String playerTwoName = "";

private String answerFromArray = "";

private String answerButtonText = "";

private Random randomQuestionNumber = new Random();

private int randomQuestion = 0;


@FXML
private void handleStartGame(ActionEvent event) {

    // ******* DECLARE VARIABLES ********

    playerOneName = player1.getText(); //Saves the name for later use
    playerTwoName = player2.getText(); //Saves the name for later use

    score1.setText(playerOneName+ " has: 0 points;");
    score2.setText(playerTwoName+ " has: 0 points;");

    playerOneScore = 0;
    playerTwoScore = 0;

    System.out.println(playerOneName + " TEST"); //To TEST if the name is saved
    System.out.println(playerTwoName + " TEST"); //To TEST if the name is saved

    // ******* DECLARE QUESTION ARRAY ********

    questionsArray.add("Question 1");
    questionsArray.add("Question 2");
    questionsArray.add("Question 3");
    questionsArray.add("Question 4");
    questionsArray.add("Question 5");
    questionsArray.add("Question 6");

    // ******* DECLARE ANSWER ARRAY ********

    answerArray.add("True");
    answerArray.add("True");
    answerArray.add("False");
    answerArray.add("True");
    answerArray.add("False");
    answerArray.add("True");

    // ******* THIS IS THE PLAYER STARTING THE ROUND ******

    player = 1;

    // ****** RETRIEVE AND PRESENT FIRST QUESTION - THIS WILL ONLY BE USED TO START THE PROGRAM ******
    randomQuestion = randomQuestionNumber.nextInt(questionsArray.size()); // GENERATES A RANDOM NUMBER TO PICK A RANDOM QUESTION FROM ARRAYLIST
    statusText.setText("Question: " + questionsArray.get(randomQuestion)); // PRINTS THE RANDOM QUESTION TO THE UI

    currentPlayer.setText("Current Player: "+playerOneName);

    buttonFalse.setDisable(false);
    buttonTrue.setDisable(false);
    startGame.setDisable(true);
}

@FXML
private void handleButtonAnswer(ActionEvent event) {
    Button answerButtonClicked = (Button) event.getSource();

    answerButtonText = answerButtonClicked.getText();
    answerFromArray = answerArray.get(randomQuestion); // PICKS THE ANSWER MATCHING THE QUESTION GENERATED BY THE RANDOM NUMBER

    if (answerFromArray.equals(answerButtonText)) {
        statusText.setText("Answer was correct! You've been awarded 1 point");
        if(player == 1){
            playerOneScore = playerOneScore+1;
            score1.setText(playerOneName+ " has: "+playerOneScore+" points;");
        }else if(player == 2){
            playerTwoScore = playerTwoScore+1;
            score2.setText(playerTwoName+ " has: "+playerTwoScore+" points;");
        }
    }else{
        statusText.setText("Answer was incorrect! No point was given.");
    }
    nextRound.setDisable(false);
    buttonFalse.setDisable(true);
    buttonTrue.setDisable(true);
}

@FXML
private void handleButtonNext(ActionEvent event) {
    if(player == 1){
        player = 2;
        currentPlayer.setText("Current Player: "+playerTwoName);
    }else if(player == 2){
        player = 1;
        currentPlayer.setText("Current Player: "+playerOneName);
    }
    questionsArray.remove(randomQuestion); // REMOVES QUESTION FROM ARRAYLIST
    answerArray.remove(randomQuestion); // REMOVES ANSWER FROM ARRAYLIST
    remainingQuestions = questionsArray.size();
    questionsLeft.setText(remainingQuestions + " questions left");
    if(questionsArray.size()!=0){
        randomQuestion = randomQuestionNumber.nextInt(questionsArray.size());
        statusText.setText("Question: " + questionsArray.get(randomQuestion)); // PRINTS QUESTION TO THE UI
    }else{
        if(playerOneScore>playerTwoScore){
            questionsLeft.setText("Game is over. The winner is: "+playerOneName);
        }else if(playerTwoScore>playerOneScore){
            questionsLeft.setText("Game is over. The winner is: "+playerTwoName);
        }else{
            questionsLeft.setText("The game ended in a DRAW. ");
        }
        startGame.setDisable(false);
        buttonFalse.setDisable(true);
        buttonTrue.setDisable(true);
    }
    nextRound.setDisable(true);
    buttonFalse.setDisable(false);
    buttonTrue.setDisable(false);
}
}

fxml

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

<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>


    <Label layoutX="233.0" layoutY="46.0" prefHeight="66.0" prefWidth="334.0" text="Java ExpertQuiz" textAlignment="CENTER">
        <font>
            <Font name="Cambria Bold" size="45.0" />
        </font>
    </Label>
    <TextField fx:id="player1" layoutX="79.0" layoutY="154.0" opacity="0.5" prefHeight="39.0" prefWidth="201.0" promptText="Enter name for player 1" />
    <TextField fx:id="player2" layoutX="503.0" layoutY="154.0" opacity="0.5" prefHeight="39.0" prefWidth="222.0" promptText="Enter name for player 2" />
    <Text fx:id="score1" layoutX="114.0" layoutY="224.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Player 1 has: 0 points" />
    <Text fx:id="score2" layoutX="558.0" layoutY="224.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Player 2 has: 0 points" />
    <Text fx:id="statusText" layoutX="41.0" layoutY="315.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Question" textAlignment="CENTER" wrappingWidth="717.1240234375">
        <font>
            <Font size="38.0" />
        </font>
    </Text>
    <Button fx:id="startGame" layoutX="363.0" layoutY="161.0" mnemonicParsing="false" onAction="#handleStartGame" text="Start game" />

    <Text fx:id="questionsLeft" layoutX="304.0" layoutY="473.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Questions left: " textAlignment="CENTER" wrappingWidth="191.9072265625">
     <font>
        <Font size="18.0" />
     </font></Text>
    <Button fx:id="buttonTrue" disable="true" layoutX="150.0" layoutY="378.0" mnemonicParsing="false" onAction="#handleButtonAnswer" text="True" />
    <Button fx:id="buttonFalse" disable="true" layoutX="592.0" layoutY="378.0" mnemonicParsing="false" onAction="#handleButtonAnswer" text="False" />
    <Button fx:id="nextRound" disable="true" layoutX="354.0" layoutY="378.0" mnemonicParsing="false" onAction="#handleButtonNext" text="Next Question" />
  <Text fx:id="currentPlayer" layoutX="355.0" layoutY="260.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Current player:">
     <font>
        <Font size="14.0" />
     </font>
  </Text>
</children>

Upvotes: 0

Views: 1873

Answers (1)

Unsolved Cypher
Unsolved Cypher

Reputation: 1583

Instead of thinking of it as pausing the loop, you can instead make the loop a separate function and then just call it when the button is placed. In this case, it wouldn't be a loop anymore, it would just have to store the index of the loop as a variable outside of the function, or you could call the function with the index as a parameter. I think your whole handleStartGame could be split up more. A good rule of thumb is that one function should be doing one specific task, which would make the program much easier to work with going forward. Feel free to leave a comment if you're having trouble with any of this!

Upvotes: 1

Related Questions