LiL
LiL

Reputation: 31

Updating JLabel text output for counter not working

So I am creating a number guessing game. The computer generates a random number, the user inputs a guess, then the computer lets the user know if they've won, or if the guess was less than or more than the random number. This goes on until they've got it right, or press play again (which resets it).

I want to count and display the number of guesses a user makes each round. So I am incrementing 'tallyValue' for each guess. I know it is counting and incrementing the values correctly. However for instance if the user guesses twice in a row values that are less than the random number, then the tally value doesn't update on the .setText output. It will only update when the users guesses alternate from less than the random number to more than the random number.

What am I missing? I've tried removing and then setting the text but I don't understand why this happens.

MyFrame() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //exit out of app 
        this.setLayout(new FlowLayout());

        //add labels, buttons and input fields
        button = new JButton("Submit");
        button.addActionListener(this); //can just pass in this because we already pass actionlistener above

        JLabel instruction = new JLabel();
        instruction.setText("Input Your Guess (must be between 1 and 100");

        textField = new JTextField();
        textField.setPreferredSize(new Dimension(250,40));

        tally = new JLabel();
        tally.setText("Number of guesses: " + tallyValue);

        outputMessage = new JLabel();
        outputMessage.setText("Take a guess!");

        playAgainButton = new JButton("Play Again");
        playAgainButton.addActionListener(this);

        this.add(instruction);
        this.add(textField);
        this.add(button);
        this.add(playAgainButton);
        this.add(outputMessage);
        this.add(tally);
        this.setTitle("Number Guessing Game");
        this.setVisible(true); //make frame visible
        this.pack(); //frame size adjusts to components

        ImageIcon icon = new ImageIcon("res/game-icon.png"); //creates an image icon
        this.setIconImage(icon.getImage());//changes icon of frame

        System.out.println(randomNumber); //for testing purposes
    }

    //add any unimplemented methods because we are using an interface
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==button) {
            int textFieldValue;

            this.remove(outputMessage);
            try {
                textFieldValue = Integer.parseInt(textField.getText());
                //if guess is correct
                if(textFieldValue == randomNumber) {
                    outputMessage.setText("Congratulations you guessed correctly!");
                    this.add(outputMessage);

                    tallyValue++;
                    
                    displayCount(tallyValue);

                    this.pack();
                    textFieldValue = 0; //reset text field val
                    
                    
                }
                //if guess is less than randomNumber
                if(textFieldValue < randomNumber) {
                    outputMessage.setText("Incorrect - the number I am thinking of is more than that");
                    this.add(outputMessage);

                    tallyValue++;
                    
                    displayCount(tallyValue);
                    
                    this.pack();
                    textFieldValue = 0; //reset text field val
                    
                }
                //if guess is more than randomNumber
                if(textFieldValue > randomNumber) {
                    outputMessage.setText("Incorrect - the number I am thinking of is less than that");
                    this.add(outputMessage);

                    tallyValue++;
                    System.out.println(tallyValue);
                    displayCount(tallyValue);

                    this.pack();
                    textFieldValue = 0; //reset text field val
                    
                }
             }
            catch (NumberFormatException ex){
                outputMessage.setText("You must insert a valid number");
                this.add(outputMessage);
                this.pack();
            }
        }

        if(e.getSource()==playAgainButton) {
            System.out.println("pa");
            this.remove(outputMessage);
            randomNumber = rand.nextInt(101);
            outputMessage.setText("Take a guess!");
            this.add(outputMessage);

            
            tallyValue = 0;
            displayCount(tallyValue);
            
            this.pack();
        }
    }

    private void displayCount (int tv) {
        this.remove(tally);
        tally.setText("Number of guesses:" + tv);
        this.add(tally);
        this.pack();
    }

Upvotes: 0

Views: 143

Answers (1)

camickr
camickr

Reputation: 324137

It will only update when the users guesses alternate from less than the random number to more than the random number.

  1. There is no need to increment the tally in 3 different places. The tally should be incremented right after you Integer.parseInt(...) statement. That is it will be updated every guess, no matter what the guess is.

  2. Then you would just update the text of your tally label with the new count. There is no need to remove/add the label from the frame. There is no need to pack() the frame. Just setting the text will cause the label to repaint. So there is no need for the displayCount() method.

You should also be learning how to use layout manager correctly. Currently you are using a FlowLayout will will just cause the components to display in a row and then wrap to the next line. This is not a very effective layout as all the components will shift if the frame is ever resized.

Read the Swing tutorial on Layout Managers. You can nest panels with different layout managers to achieve a more flexible layout.

    textField = new JTextField();
    textField.setPreferredSize(new Dimension(250,40));

Don't use magic numbers for the size of a component. Instead use the API properly so the text field can determine its own preferred size:

    textField = new JTextField(10);

The "10" will allow the text field to size itself to display 10 "W" characters before scrolling of the text.

Also, you should not use a shared ActionListener for your buttons.

One approach is to use a lamba to separate the functionality:

//playAgainButton.addActionListener(this);
playAgainButton.addActionListener((e) -> playAgain());

Then you create a private method playAgain() in your class. Now the code is separated into methods by function.

Upvotes: 3

Related Questions