2

I'm trying to add a while loop to count the number of attempts made and add it to the message in my GUI. After adding the while loop the program freezes, but no errors output to the console.

I've tested it without a GUI and got it to print using System.out.print fine, but I can't get this to even allow a second input. I have to stop the code from running to quit out.

Any advice would be appreciated!

import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.*;
import javax.swing.SwingConstants;
import java.awt.Font;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class GuessingGame extends JFrame {
private JTextField txtGuess;
private JLabel lblOutput;
private int theNumber;
private int attempt;
public void checkGuess() {
    String guessText = txtGuess.getText();
    String message = "";
    try {

        int guess = Integer.parseInt(guessText);
        while(guess!=theNumber) {
            if (guess < 0 || guess >100) {
                message = "Please enter a number between 0 and 100";
                attempt++;
            }
            else if (guess < theNumber) {
                message = guess + " is too low. Try again.";
                attempt++;
            }
            else if (guess > theNumber) {
                message = guess + " is too high. Try again.";
                attempt++;
            }
            else {
                message = guess + " is correct! It took " + attempt+ " attempts. Starting new game.";
                attempt++;
                newGame();
            }
        }
    } 
        catch(Exception e) {
        message= "Enter a whole number between 0 and 100";
    } 
        finally {
            lblOutput.setText(message);
            txtGuess.requestFocus();
            txtGuess.selectAll();
        }
}
public void newGame() {
    theNumber = (int)(Math.random() * 100 + 1);
    }

public GuessingGame() {
    setTitle("Hi-Lo Guessing Game");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    getContentPane().setLayout(null);

    JLabel lblHiloGuessingGame = new JLabel("Hi-Lo Guessing Game");
    lblHiloGuessingGame.setFont(new Font("Tahoma", Font.BOLD, 15));
    lblHiloGuessingGame.setHorizontalAlignment(SwingConstants.CENTER);
    lblHiloGuessingGame.setBounds(12, 35, 408, 16);
    getContentPane().add(lblHiloGuessingGame);

    JLabel lblGuessANumber = new JLabel("Guess a number between 1 and 100");
    lblGuessANumber.setHorizontalAlignment(SwingConstants.CENTER);
    lblGuessANumber.setBounds(58, 86, 245, 16);
    getContentPane().add(lblGuessANumber);

    txtGuess = new JTextField();
    txtGuess.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            checkGuess();
        }
    });
    txtGuess.setBounds(310, 85, 32, 19);
    getContentPane().add(txtGuess);
    txtGuess.setColumns(10);

    JButton btnGuess = new JButton("Guess!");
    btnGuess.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
        checkGuess();
        }
        });
    btnGuess.setBounds(163, 137, 97, 25);
    getContentPane().add(btnGuess);

    lblOutput = new JLabel("Enter a number and click guess");
    lblOutput.setHorizontalAlignment(SwingConstants.CENTER);
    lblOutput.setFont(new Font("Tahoma", Font.ITALIC, 13));
    lblOutput.setBounds(84, 197, 265, 19);
    getContentPane().add(lblOutput);
}

public static void main(String[] args) {
    GuessingGame theGame = new GuessingGame();
    theGame.newGame();
    theGame.setSize(new Dimension(450,300));
    theGame.setVisible(true);
    }

}

4
  • Have you tried stepping through this with your debugger? Commented Jun 19, 2019 at 5:23
  • 1
    Swing is single threaded (and not thread safe) - see Concurrency in Swing for more details. Swing is, like most GUI frameworks, also event driven, that is, something happens and you respond to it. You need to stop thinking in such a linear manner Commented Jun 19, 2019 at 5:24
  • checkGuess shouldn't need a loop Commented Jun 19, 2019 at 5:25
  • Thanks for the tips everyone. MadProgrammer was right, I just took out the while loop and it worked how I wanted. I bookmarked the Concurrency in Swing link because after reviewing, it seemed like it'll be useful later. Still a novice and this was my first time trying to build a GUI. everything helps! Commented Jun 19, 2019 at 5:56

1 Answer 1

1

I don't think you need an action performed handler for the text field, because doing anything to the text field shouldn't count as an attempt, right? Only pressing the Guess button counts as an attempt.

So you can delete this:

txtGuess.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        checkGuess();
    }
});

Now checkGuess will be called whenever the user presses the button. Right now, it will parse the number from the text field, and enter a while loop to check that number. However, since guess is never modified in the while loop, the while loop never breaks.

Even if you read the guess inside the while loop, guess still wouldn't change, because while the while loop is running, the user cannot interact with the UI.

A better way to do this, is to simply remove the while loop:

public void checkGuess() {
    String guessText = txtGuess.getText();
    String message = "";
    try {

        int guess = Integer.parseInt(guessText);
        if (guess < 0 || guess >100) {
            message = "Please enter a number between 0 and 100";
            attempt++;
        }
        else if (guess < theNumber) {
            message = guess + " is too low. Try again.";
            attempt++;
        }
        else if (guess > theNumber) {
            message = guess + " is too high. Try again.";
            attempt++;
        }
        else {
            message = guess + " is correct! It took " + attempt+ " attempts. Starting new game.";
            attempt++;
            newGame();
        }
    } 
        catch(Exception e) {
        message= "Enter a whole number between 0 and 100";
    } 
        finally {
            lblOutput.setText(message);
            txtGuess.requestFocus();
            txtGuess.selectAll();
        }
}

Although it seems like you need a while loop here, you actually don't. This is because checkGuess will be called every time you press the Guess button.

Unlike in a command line, you don't ask for input in a GUI program, you wait for it.

Sign up to request clarification or add additional context in comments.

1 Comment

thank you for the feedback! someone commented about not needing the while loop and taking it out fixed it, but your notes were very helpful. It's my first time trying to build a GUI and reading this was an "ah hah" moment

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.