program suppose to run "Guess the number" game
after guessing the number correctly , there's an option to start over
Pressing the "playAgainBtn" make the program stuck.
Another issue is after guessing the "guessText" cant be .selectAll
any insight will be welcomed
Tnx.
public class GuessTheNumberGame extends JFrame
{
private int randomNumber;
private boolean correctGuess;
private JLabel startMsg;
private JLabel enterGuessJLabel;
private JButton playAgainBtn;
private JLabel msgToPlayer;
private JTextField guessText;
private int previousGuess; // previous guessed number hot/cold
private int numOfGuess;
private Container container;
public GuessTheNumberGame()
{
container = getContentPane();
startMsg = new JLabel();
enterGuessJLabel = new JLabel();
guessText = new JTextField(10);
guessText.addActionListener(
new ActionListener()
{
#Override
public void actionPerformed(ActionEvent event)
{
int playerGuess = Integer.parseInt(event.getActionCommand());
if ( playerGuess == randomNumber )
{
msgToPlayer.setText("Great ! u guessed in " + numOfGuess + "Guesses");
correctGuess = true;
}
else
{
wrongGuess(playerGuess);
}
}
}
);
msgToPlayer = new JLabel("");
playAgainBtn = new JButton("Play Again");
ButtonHandler buttonHandler = new ButtonHandler();
playAgainBtn.addActionListener(buttonHandler);
setLayout(new FlowLayout());
add(startMsg);
add(enterGuessJLabel);
add(guessText);
add(msgToPlayer);
add(playAgainBtn);
}
protected class ButtonHandler implements ActionListener
{
#Override
public void actionPerformed(ActionEvent event)
{
startGame();
}
}
public void startGame()
{
previousGuess = 1000;
numOfGuess = 1;
correctGuess = false;
Random rand = new Random();
randomNumber = rand.nextInt(1000) + 1;
startMsg.setText( "I have a number between 1 and 1000. can you Guess my Number?" );
playAgainBtn.setVisible( false );
while ( !correctGuess)
{
enterGuessJLabel.setText( "Please enter your " + numOfGuess + " guess: " );
}
playAgainBtn.setVisible(true);
}
private void wrongGuess(int playerGuess)
{
numOfGuess++;
if ( Math.abs(playerGuess - randomNumber) > previousGuess )
container.setBackground( Color.GREEN);
else
container.setBackground( Color.RED);
previousGuess = Math.abs(playerGuess - randomNumber);
if (playerGuess > randomNumber)
msgToPlayer.setText("Too High");
else
msgToPlayer.setText( "Too Low" );
}
}
When you start the application, startGame() runs on the main thread, which is OK. When you press playAgainBtn, it calls startGame() on the AWT Dispatch Thread, thus tying up this thread, prohibiting the AWT from processing events. Try this to free up the AWT Dispatch Thread:
protected class ButtonHandler implements ActionListener
{
#Override
public void actionPerformed(ActionEvent event)
{
new Thread() {
#Override
public final void run() {
startGame();
}
}.start();
}
}
The problem is that your startGame method, called when the button is clicked, has an infinite loop in it.
while ( !correctGuess)
{
enterGuessJLabel.setText( "Please enter your " + numOfGuess + " guess: " );
}
The correctGuess variable will never be changed so your program will just execute the setText command endlessly.
The way Swing (and all GUI frameworks) work is that you must always respond to an event such as a button click and then return control.
Related
I am creating a simple GUI with an increment and reset JButton and a JTextField that outputs the counting number. The layout of the GUI is fine but I am having trouble with implementing my action listeners, here is where I create my buttons and assign the associated action listener to the variable:
JTextField t = new JTextField(40);
t.setText("Button Clicked " + 0 + " times");
JButton b1 = new JButton("Increment");
b1.addActionListener(new Incrementer(t));
JButton b2 = new JButton("Reset");
b2.addActionListener(new Reset(t));
This is in a class along with the other layout specifications. Here is my incrementer class which should increment the counter by 1:
class Incrementer implements ActionListener {
JTextField t = new JTextField();
public Incrementer (JTextField t) {
this.t = t;
}
public void actionPerformed(ActionEvent e) {
t.getText();
int numClicks = Integer.parseInt(t.getText());
numClicks++;
t.setText("Button Clicked " + numClicks + " times");
}}
and my reset class which should reset the count to 0:
class Reset implements ActionListener {
JTextField t = new JTextField();
public int numClicks = 0;
public Reset (JTextField t) {
this.t = t;
}
public void actionPerformed(ActionEvent e) {
int numClicks = Integer.parseInt(t.getText());
numClicks = 0;
t.setText("Button Clicked " + numClicks + " times");
}}
I originally was having an issue where each action listener had its own numClicks value, for example I would click the increment counter 3 times, then reset to 0 and when I clicked increment again it would resume the count at 4 rather than 1. After trying to fix that I now cannot even click my increment and reset buttons as I get a nasty list of errors such as: java.lang.NumberFormatException. I have tried to work out what is wrong with my code but cannot find out what that is.
Using a text field (which basically is a string) for working on a count value is not a good design approach. The exception you get is a consequence of the text you are storing in the text field: "Button Clicked x times". This is not a number.
So better use a separate model. You could add a new class for counting:
class Counter {
private int count;
int getCount() { return count; }
void increment() { count += 1; }
void reset() { count = 0; }
// maybe some more methods ...
}
Now in your GUI class you do:
Counter counter = new Counter();
JTextField t = new JTextField(40);
t.setText("Button Clicked " + 0 + " times");
JButton b1 = new JButton("Increment");
b1.addActionListener(new Incrementer(counter, t));
JButton b2 = new JButton("Reset");
b2.addActionListener(new Reset(counter, t));
See that the action listeners get the same reference to one counter. Obviously you must then design your action listeners this way:
class Incrementer implements ActionListener {
private final Counter counter;
private final JTextField textfield;
Incrementer(Counter counter, JTextField textfield) {
this.counter = counter;
this.textfield = textfield;
}
#Override
public void actionPerformed(ActionEvent e) {
counter.increment();
textfield.setText("Button Clicked " + counter.getCount() + " times");
}
}
The Reset class looks analogue. This is a bit like MVC.
I got the widow and the buttons into the GUI but for the life of me I can't get anything to output. I am suppose to enter a guess, and from a random number the game generates. It is suppose to tell me if I'm too high, too low or correct. Also, if it is not correct it's supposed to tell me if I am warm or cold. If any one could point me in the right direction on this I would be grateful. I don't know what I'm doing wrong on this. I have researched different topics but with the different ways to solve this problem none match what I was looking for.
Here's the code:
//all necessary imports
public class GuessGame extends JFrame
{
private static final long serialVersionUID = 1L;
private JFrame mainFrame;
private JTextField guessField;
private JLabel message1;
private JLabel message2;
private JLabel message3;
private JLabel message4;
private JLabel guessLabel;
private JLabel tooHigh;
private JLabel tooLow;
private JButton guessButton;
private JButton newGame;
private JButton exitButton;
private int randomNum = 0;
private final int MAX_NUM = 1000;
private final int MIN_NUM = 1;
private int guessCount;
private int lastDistance;
public GuessGame()
{
mainFrame = new JFrame();
guessField = new JTextField(4);
message4 = new JLabel("I have a number between 1 and 1000 -- can you guess my number?") ;
guessLabel = new JLabel("Please Enter Your Guess:");
guessButton = new JButton("Guess");
newGame = new JButton("New Game");
exitButton = new JButton("Exit");
Container c = mainFrame.getContentPane();
c.setLayout(new FlowLayout());
c.setBackground(Color.CYAN);
c.add(message4);
c.add(guessLabel);
c.add(guessField);
c.add(guessButton);
c.add(newGame);
c.add(exitButton);
newGame.setMnemonic('N');
exitButton.setMnemonic('E');
guessButton.setMnemonic('G');
mainFrame.setSize(420, 300);//Sets width and height of Window
mainFrame.setVisible(true);//Allows GUI to be visible
mainFrame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
GuessButtonsHandler gHandler = new GuessButtonsHandler();
guessField.addActionListener(gHandler);
ExitButtonsHandler eHandler = new ExitButtonsHandler();
exitButton.addActionListener(eHandler);
NewGameButtonsHandler nHandler = new NewGameButtonsHandler();
newGame.addActionListener(nHandler);
}
class GuessButtonsHandler implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
Random rand = new Random();
int guess = 0;
int currDistance = 0;
boolean correct = false;
guess = Integer.parseInt(guessField.getText());//Converts String to Integer
if(guessCount == 0)
{
lastDistance = MAX_NUM;
}
if(guess >= MIN_NUM && guess <= MAX_NUM)
{
guessCount += 1;
}
if(guess > randomNum)
{
tooHigh.setText("Number To High!!!");
guessCount += 1;
}
else if(guess > randomNum)
{
tooLow.setText("Number To Low!!!");
guessCount += 1;
}
else
{
correct = true;
message2.setText("Correct!!!");
message2.setBackground(Color.GREEN);
guessField.setEditable(false);
}
if(!correct)
{
currDistance = Math.abs(guess - randomNum);
}
if(currDistance <= lastDistance)
{
message3.setText("You are getting warmer!!!");
mainFrame.add(message3).setBackground(Color.RED);
}
else
{
message4.setText("You are getting colder!!!");
mainFrame.add(message4).setBackground(Color.BLUE);
}
lastDistance = currDistance;
randomNum = rand.nextInt(1000) + 1;
}
}
class NewGameButtonsHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Random rand = new Random();
randomNum = rand.nextInt(1000) + 1;
guessCount = 0;
}
}
class ExitButtonsHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
}
}
public class GuessGameTest {
public static void main(String[] args)
{
new GuessGame();
}
}
You need to:
Add gHandler as a listener to the button too, not only to the text field:
guessField.addActionListener(gHandler);
guessButton.addActionListener(gHandler);
Keeping it in the text field too is a good idea: then the guess can be triggered by pressing enter too, not just clicking the button (this part actually works in your code).
You need to initialize the message labels, and add them somewhere. You have additions commented out, but the initializations are missing.
You don't really need labels for all possible messages. You want to display only a message for too high, too low, or correct guess at a time. Not two or more simultaneously. So one field is enough, just set the correct text.
You have the condition inverted when checking too low numbers.
You generate a new random number after each guess, so the "getting warmer" messages are not very useful. Also you don't need to create a new Random object every time you want a new random number.
Possibly others too, but hopefully these help you forward.
I have been having some problems with using the Timer function of Java swing. I am fairly new to programming with Java, so any help is greatly appreciated. I have looked over many other Timer questions on this site but none of them have answered my question. I have made a GUI that allows you to play rock paper scissors, where you can choose from clicking three buttons. I want my program to sleep for around 1 second after you click the button, and again after it displays a message. After I realized Thread.sleep() wouldn't work for my GUI, I tried to implement a timer.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.Border;
import java.io.*;
public class rps {
//ROCK PAPER SCISSORS
static JLabel middle = new JLabel();
static JLabel them = new JLabel();
static JLabel yourWins = new JLabel();
static JLabel theirWins = new JLabel();
static JPanel yourPanel = new JPanel();
static JPanel middlePanel = new JPanel();
static JLabel blank1 = new JLabel();
static JLabel blank2 = new JLabel();
static JButton rock = new JButton("Rock");
static JButton paper = new JButton("Paper");
static JButton scissors = new JButton("Scissors");
static int yw = 0;
static int tw = 0;
static ButtonHandler listener = new ButtonHandler();
public static void main(String[] args) {
//Create the frame
JFrame frame = new JFrame("Rock Paper Scissors");
frame.setSize(500, 500); //Setting the size of the frame
middle.setFont(new Font("Serif", Font.PLAIN, 30));
middle.setHorizontalAlignment(SwingConstants.CENTER);
them.setFont(new Font("Serif", Font.PLAIN, 15));
them.setHorizontalAlignment(SwingConstants.CENTER);
yourWins.setHorizontalAlignment(SwingConstants.CENTER);
theirWins.setHorizontalAlignment(SwingConstants.CENTER);
//Creating panels
JPanel bigPanel = new JPanel();
Border border = BorderFactory.createLineBorder(Color.BLACK, 1);
Border wlb = BorderFactory.createLineBorder(Color.RED, 1);
them.setBorder(border);
yourPanel.setBorder(border);
bigPanel.setBorder(border);
yourWins.setBorder(wlb);
theirWins.setBorder(wlb);
middlePanel.setBorder(border);
//Creating grid layouts
GridLayout yourGrid = new GridLayout(1,3,10,10);
GridLayout theirGrid = new GridLayout(1,1); //One row, one column
GridLayout middleGrid = new GridLayout(5,1);
GridLayout bigGrid = new GridLayout(3,1);//Two rows, one column
//Setting the layouts of each panel to the grid layouts created above
yourPanel.setLayout(yourGrid); //Adding layout to buttons panel
them.setLayout(theirGrid); //Adding layout to label panel
middlePanel.setLayout(middleGrid);
bigPanel.setLayout(bigGrid);
//Adding r/p/s to your grid.
yourPanel.add(rock);
yourPanel.add(paper);
yourPanel.add(scissors);
//Adding w/l rations to middlegrid.
middlePanel.add(theirWins);
middlePanel.add(blank1);
middlePanel.add(middle);
middlePanel.add(blank2);
middlePanel.add(yourWins);
//Attaching the listener to all the buttons
rock.addActionListener(listener);
paper.addActionListener(listener);
scissors.addActionListener(listener);
bigPanel.add(them);
bigPanel.add(middlePanel);
bigPanel.add(yourPanel);
//Shows the score at 0-0.
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
frame.getContentPane().add(bigPanel); //panel to frame
frame.setVisible(true); // Shows frame on screen
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
//Class represents what do when a button is pressed
private static class ButtonHandler implements ActionListener {
public void actionPerformed (ActionEvent e) {
Timer timer = new Timer(1000, this);
String tc = random();
them.setText("They chose: " + tc + "!");
if (e.getSource() == rock) {
whoWins("rock", tc);
} else if (e.getSource() == paper) {
whoWins("paper", tc);
} else if (e.getSource() == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
timer.setRepeats(false);
timer.start();
}
}
public static String random() {
int random = (int) (Math.random() * 3);
if (random == 0) {
return "Rock";
} else if (random == 1) {
return "Paper";
} else if (random == 2) {
return "Scissors";
}
return "";
}
public static void whoWins(String yc, String tc) {
if (yc.equals("rock")) {
if (tc.equals("Rock")) {
middle.setText("It's a tie!");
} else if (tc.equals("Paper")) {
middle.setText("You lose!");
tw++;
} else if (tc.equals("Scissors")) {
middle.setText("You win!");
yw++;
}
} else if (yc.equals("paper")) {
if (tc.equals("Rock")) {
middle.setText("You win!");
yw++;
} else if (tc.equals("Paper")) {
middle.setText("It's a tie!");
} else if (tc.equals("Scissors")) {
middle.setText("You lose!");
tw++;
}
} else if (yc.equals("scissors")) {
if (tc.equals("Rock")) {
middle.setText("You lose!");
tw++;
} else if (tc.equals("Paper")) {
middle.setText("You win!");
yw++;
} else if (tc.equals("Scissors")) {
middle.setText("It's a tie!");
}
}
}
}
What is actually happening is there is no delay from when I press the button to a message displaying, because clearly I am not using the timer correctly. I would like the timer to just run once, and after it runs the code will execute. However, when I click a button the timer will run on repeat although setRepeats is false. Therefore, the message I want to display, instead of being delayed, is displayed instantaneously but then goes on a loop and keeps displaying a message (the message is random) until I shut off the program. If I click the button again, it will double the tempo of the timer it seems, and the messages display twice as fast and so on and so forth.
them.setText("They chose: " + tc + "!");
This is the message that is displayed on repeat, with the variable tc changing every time. The timer seems to just be displaying this message every timer interval (1s).
Any help would be greatly appreciated.
EDIT:
So I added this section :
private static class ButtonHandler implements ActionListener {
public void actionPerformed (ActionEvent e) {
// I'd be disabling the buttons here to prevent
// the user from trying to trigger another
// update...
// This is an instance field which is used by your
// listener
Timer timer = new Timer(1000, listenert);
timer.setRepeats(false);
timer.start();
}
}
private static class timer implements ActionListener {
public void actionPerformed (ActionEvent e) {
String tc = random(); //A method that chooses a random word.
them.setText("They chose: " + tc + "!");
if (e.getSource() == rock) {
whoWins("rock", tc); //whoWins is a method that will display a message.
} else if (e.getSource() == paper) {
whoWins("paper", tc);
} else if (e.getSource() == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
// Start another Timer here that waits 1 second
// and re-enables the other buttons...
}
}
so what I believe happens now is when I click a button, the buttonhandler listener starts the timer which is attached to the timer listener (named listenert) which will run the code in the actionPerformed of the timer class. however the sleep function still is not working
EDIT 2.5:
private static class ButtonHandler implements ActionListener {
public void actionPerformed (ActionEvent e) {
final JButton button = (JButton)e.getSource();
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
String tc = random();
them.setText("They chose: " + tc + "!");
if (button == rock) {
whoWins("rock", tc);
} else if (button == paper) {
whoWins("paper", tc);
} else if (button == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
}
});
timer.setRepeats(false);
timer.start();
}
}
that is what I have so far, I just need to add antoher sleep after
them.setText("They chose: " + tc + "!");
where would I put a timer.restart() if any? the timer.start() is at the end of the method which I don't quite understand.
So, the ActionListener you supply to the Timer is notified when the timer "ticks", so you ButtonHandler actionPerformed should look more like...
public void actionPerformed (ActionEvent e) {
// I'd be disabling the buttons here to prevent
// the user from trying to trigger another
// update...
// This is an instance field which is used by your
// listener
choice = e.getSource();
Timer timer = new Timer(1000, listener);
timer.setRepeats(false);
timer.start();
}
And your listener should look more like
public void actionPerformed (ActionEvent e) {
String tc = random(); //A method that chooses a random word.
them.setText("They chose: " + tc + "!");
if (choice == rock) {
whoWins("rock", tc); //whoWins is a method that will display a message.
} else if (choice == paper) {
whoWins("paper", tc);
} else if (choice == scissors) {
whoWins("scissors", tc);
}
yourWins.setText("Your wins: " + yw);
theirWins.setText("Their wins: " + tw);
// Start another Timer here that waits 1 second
// and re-enables the other buttons...
}
For example...
You may consider taking a look at How to use Swing Timers for more details
Updated
Start with a simple example...
public class TestPane extends JPanel {
private JLabel label;
private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
public TestPane() {
setLayout(new GridBagLayout());
label = new JLabel();
add(label);
tick();
Timer timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
tick();
}
});
timer.start();
}
protected void tick() {
label.setText(sdf.format(new Date()));
}
}
This just calls the tick method every half second to update the time on the JLabel...
firstly import the following ;
import java.awt.event.ActionEvent ;
import java.awt.event.ActionListener ;
import javax.swing.Timer ;
then initialize the timer at the end of the form like this ;
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new mainprogramme().setVisible(true);
}
});
}
private Timer timer ;
then after initializing the timer add a public class like following;
public class progress implements ActionListener {
public void actionPerformed(ActionEvent evt){
int n = 0 ;
if (n<100){
n++ ;
System.out.println(n) ;
}else{
timer.stop() ;
}
}
}
after you do this go to the j Frame>right click and select>Events>window>window Opened and type the following ;
private void formWindowOpened(java.awt.event.WindowEvent evt) {
timer = new Timer(100,new progress()) ;
and after you do all this take a button name it as anything and type the following in its void like following ;
timer.start();
AND THAT'S IT CODE IT AND THEN REPLY ME...
I have a game that I wrote with Java that runs perfectly on command line. However, I've been building a GUI for it and have been changing it so it runs on the GUI but I'm having issues. It's a hangman game that allows the player to guess letters to try to guess the hangman word. If the player makes a correct guess, the game displays a certain message, and if the player makes an incorrect guess, the game displays a different message. The game stops working after I've made two guesses using the GUI version though... I've been trying to fix it for a couple of days but no luck...I've tried calling javax.swing.SwingUtilities.invokeLater but it's still giving me issues.
Any help would be appreciated, heres the code (p.s. I'm still in the process of moving stuff from command line to GUI):
import java.util.ArrayList;
import java.util.Scanner;
public class HangmanTwo {
private String[] wordList = {"apple", "orange"};
private String chosenWord;
private String playerGuess;
private int numberOfIncorrectGuesses = 0;
private boolean playerWon = false;
private boolean playerPlaying = false;
public static String uInput1;
private boolean start = false;
private ArrayList<String> lettersOfChosenWord;
private ArrayList<String> incorrectGuessArrayList2 = new ArrayList<String>();
private ArrayList<String> underScores;
private boolean showHangman = false;
HangmanGuiGui hh = new HangmanGuiGui();
//Print game instructions to player
void printGameInstructions() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
hh.buildGui();
hh.textFieldSouth.requestFocus();
hh.textAreaCenter.append("Welcome to Hangman! \n");
hh.textAreaCenter.append("To play, type in a letter as your guess, then press ENTER! \n");
hh.textAreaCenter.append("If you think you know the word, type in the whole word and see if you got it right! \n");
hh.textAreaCenter.append("But be careful! Guessing the word incorrectly will cost you a limb! \n");
hh.textAreaCenter.append("To start playing, type 'start' and press ENTER. \n");
}
});
}
//Ask player if they want to start the game
void askToStart() {
uInput1 = "waitingforinput";
while (!start) {
if(uInput1.equals("waitingforinput")) {
} else if ((uInput1).equals("start")) {
start = true;
uInput1 = "waitingforInput";
} else {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
hh.textAreaCenter.append("Please type the word 'start' then press the ENTER key to begin playing. \n");
}
});
uInput1 = "waitingforinput";
}
}
}
//Game picks random word from word list
void pickRandomWord() {
int lengthOfWordList = wordList.length;
int pickRandomWord = (int) (Math.random() * lengthOfWordList);
chosenWord = wordList[pickRandomWord];
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
hh.textAreaCenter.append("The word is " + chosenWord.length() + " letters long\n");
}
});
}
//Make an arraylist to hold each letter of the chosen word at each index
void makeArrayListOfChosenWord(){
lettersOfChosenWord = new ArrayList<String> ();
for (int i = 0; i < chosenWord.length(); i++) {
lettersOfChosenWord.add(chosenWord.substring(i, i+1));
}
}
//Make an arraylist of underscores that holds as
//many underscores as letters in the chosen word
void makeArrayListUnderScore(){
underScores = new ArrayList<String>();
for (int i = 0; i < chosenWord.length(); i++) {
underScores.add("_");
}
for (int i = 0; i < underScores.size(); i++) {
//hh.textAreaWest.append((underScores.get(i)).toString());
//show the underscores in the text area
}
}
//get a guess from the player
void getPlayerGuess() {
boolean getGuess = true;
uInput1 = "waitingforinput";
while (getGuess) {
if (uInput1.equals("")) {
//javax.swing.SwingUtilities.invokeLater(new Runnable() {
//public void run() {
hh.textAreaCenter.append("Please guess a letter\n");
//}
//});
uInput1 = "waitingforinput";
} else if (uInput1.equals("waitingforinput")) {
} else {
playerGuess = uInput1;
//javax.swing.SwingUtilities.invokeLater(new Runnable() {
//public void run() {
hh.textAreaCenter.append(playerGuess + "\n");
//}
//});
getGuess = false;
}
}
}
//if the player wins, set the variable playerWon to true
void setPlayerWon(boolean a) {
playerWon = a;
}
//start the game and play it
void playGame() {
playerPlaying = true;
while (playerPlaying && !playerWon) {
getPlayerGuess();
if (playerGuess.equals(chosenWord)) {
playerPlaying = false;
wordWasGuessed();
}else if (numberOfIncorrectGuesses < 6) {
checkPlayerGuess();
if (playerWon) {
playerPlaying = false;
wordWasGuessed();
} else if (numberOfIncorrectGuesses == 6) {
playerPlaying = false;
gameOver();
}
}
}
}
//check the player's guess and see if its correct or not
void checkPlayerGuess(){
//update number of incorrect guesses
if (lettersOfChosenWord.contains(playerGuess)) {
System.out.println("Correct guess!");
if (!showHangman) {
displayNoose();
}
displayHangman();
replaceUnderScoreWithLetter();
if (!underScores.contains("_")) {
setPlayerWon(true);
}
} else if (!lettersOfChosenWord.contains(playerGuess)) {
checkIncorrectGuessArrayList();
}
}
//check the incorrectguess array list and add incorrect letters to it
void checkIncorrectGuessArrayList() {
if (incorrectGuessArrayList2.contains(playerGuess)) {
System.out.printf("You already guessed %s, try again!", playerGuess);
} else if (!incorrectGuessArrayList2.contains(playerGuess)) {
if (numberOfIncorrectGuesses < 6) {
System.out.println("You guessed wrong, try again!");
incorrectGuessArrayList2.add(playerGuess);
++numberOfIncorrectGuesses;
displayHangman();
printArrayListUnderScore();
}
}
}
//replace the underscores with a letter
void replaceUnderScoreWithLetter() {
while (lettersOfChosenWord.contains(playerGuess)) {
int indexOfPlayerGuess = lettersOfChosenWord.indexOf(playerGuess);
underScores.set(indexOfPlayerGuess, playerGuess);
lettersOfChosenWord.set(indexOfPlayerGuess, "_");
incorrectGuessArrayList2.add(playerGuess);
}
printArrayListUnderScore();
}
//show the underscores to the player
void printArrayListUnderScore() {
for (int j = 0; j < underScores.size(); j++) {
System.out.print((underScores.get(j)).toString());
}
}
void resetAllValues(int resetNumberIncorrectGuesses, boolean hangmanshow) {
numberOfIncorrectGuesses = resetNumberIncorrectGuesses;
lettersOfChosenWord.removeAll(lettersOfChosenWord);
incorrectGuessArrayList2.removeAll(incorrectGuessArrayList2);
underScores.removeAll(underScores);
showHangman = hangmanshow;
}
void displayNoose(){
System.out.println(" ___,");
System.out.println(" l ");
System.out.println(" l");
System.out.println("_l_");
}
//Display a growing hangman with each incremental wrong guess
void displayHangman(){
switch (numberOfIncorrectGuesses) {
case 1: firstWrongGuess();
showHangman = true;
break;
case 2: secondWrongGuess();
break;
case 3: thirdWrongGuess();
break;
case 4: fourthWrongGuess();
break;
case 5: fifthWrongGuess();
break;
case 6: sixthWrongGuess();
break;
}
}
void firstWrongGuess(){
System.out.println(" ___,");
System.out.println(" l o ");
System.out.println(" l");
System.out.println("_l_");
}
void secondWrongGuess(){
System.out.println(" ___,");
System.out.println(" l o ");
System.out.println(" l l");
System.out.println("_l_");
}
void thirdWrongGuess(){
System.out.println(" ___,");
System.out.println(" l o ");
System.out.println(" l /l");
System.out.println("_l_");
}
void fourthWrongGuess(){
System.out.println(" ___,");
System.out.println(" l o ");
System.out.println(" l /l\\");
System.out.println("_l_");
}
void fifthWrongGuess(){
System.out.println(" ___,");
System.out.println(" l o ");
System.out.println(" l /l\\");
System.out.println("_l_/");
}
void sixthWrongGuess(){
System.out.println(" ___,");
System.out.println(" l o ");
System.out.println(" l /l\\");
System.out.println("_l_/ \\");
}
//what happens if the chosenWord was guessed
void wordWasGuessed() {
hh.textAreaCenter.append("******\n");
hh.textAreaCenter.append("GOOD JOB! YOU GUESSED THE WORD!\n");
hh.textAreaCenter.append("You wanna play again? (y/n)\n");
resetGame(0, false, false);
boolean playAgain = false;
while (!playAgain) {
Scanner s = new Scanner(System.in);
String userInput = s.next();
if (userInput.equals("y")) {
playAgain = true;
resetAllValues(0, false);
startGame();
} else if (userInput.equals("n")) {
playAgain = true;
System.out.println("Ok...See you next time!");
} else {
System.out.println("please type y or n, then press enter!");
}
}
}
//what happens when the player loses and game is over
void gameOver() {
System.out.println("Aww you lost... the word was " + chosenWord);
System.out.println("You wanna play again? (y/n)");
resetGame(0, false, false);
boolean playAgain = false;
while (!playAgain) {
Scanner s = new Scanner(System.in);
String userInput = s.next();
if (userInput.equals("y")) {
playAgain = true;
resetAllValues(0, false);
startGame();
} else if (userInput.equals("n")) {
playAgain = true;
System.out.println("Ok...See you next time!");
} else {
System.out.println("please type y or n, then press enter!");
}
}
}
//reset the game
void resetGame(int resetNumberIG, boolean resetPlayerWon, boolean resetPlayerPlaying) {
numberOfIncorrectGuesses = resetNumberIG;
playerWon = resetPlayerWon;
playerPlaying = resetPlayerPlaying;
}
void startGame() {
pickRandomWord();
makeArrayListOfChosenWord();
makeArrayListUnderScore();
}
public static void main(String[] args) throws InterruptedException {
HangmanTwo h = new HangmanTwo();
h.printGameInstructions();
h.askToStart();
if (h.start == true) {
h.startGame();
h.playGame();
}
}
}
And GUI
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class HangmanGuiGui {
TextFieldSouthHandler tfsHandler = new TextFieldSouthHandler();
ButtonEnterHandler beHandler = new ButtonEnterHandler();
JFrame frame = new JFrame("Hangman");
JLabel label = new JLabel("Welcome to Hangman");
public JTextArea textAreaCenter = new JTextArea();
JTextField textFieldSouth = new JTextField();
JScrollPane scrollPane = new JScrollPane();
JPanel panelWest = new JPanel(new BorderLayout());
JPanel subPanelWest = new JPanel();
JTextArea textAreaWest = new JTextArea();
JPanel panelSouth = new JPanel(new BorderLayout());
JButton buttonEnter = new JButton("Enter");
//Icon aba = new ImageIcon(getClass().getResource("hangman1.jpg"));
//JLabel picLabel = new JLabel(aba);
JPanel panelEast = new JPanel();
void buildGui() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
textAreaCenter.setEditable(false);
textFieldSouth.addKeyListener(tfsHandler);
textAreaWest.setEditable(false);
buttonEnter.addActionListener(beHandler);
panelSouth.add(BorderLayout.CENTER, textFieldSouth);
panelSouth.add(BorderLayout.EAST, buttonEnter);
//subPanelWest.add(picLabel);
JPanel panelwesteast = new JPanel();
JPanel panelwestwest = new JPanel();
JPanel panelwestsouth = new JPanel();
panelWest.add(BorderLayout.SOUTH, panelwestsouth);
panelWest.add(BorderLayout.EAST, panelwesteast);
panelWest.add(BorderLayout.WEST, panelwestwest);
panelWest.add(BorderLayout.NORTH, subPanelWest);
panelWest.add(BorderLayout.CENTER, textAreaWest);
scrollPane.getViewport().setView (textAreaCenter);
frame.getContentPane().add(BorderLayout.NORTH, label);
frame.getContentPane().add(BorderLayout.CENTER, scrollPane);
frame.getContentPane().add(BorderLayout.SOUTH, panelSouth);
frame.getContentPane().add(BorderLayout.WEST, panelWest);
frame.getContentPane().add(BorderLayout.EAST, panelEast);
frame.setSize(800, 600);
frame.setVisible(true);
}
private class TextFieldSouthHandler implements KeyListener {
public void keyPressed(KeyEvent event) {
if (event.getKeyCode()==KeyEvent.VK_ENTER) {
//boolean bee = javax.swing.SwingUtilities.isEventDispatchThread();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
HangmanTwo.uInput1 = textFieldSouth.getText();
textFieldSouth.setText("");
}
});
}
}
public void keyTyped(KeyEvent event) {
}
public void keyReleased(KeyEvent event) {
}
}
private class ButtonEnterHandler implements ActionListener {
public void actionPerformed(ActionEvent event) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
HangmanTwo.uInput1 = textFieldSouth.getText();
textFieldSouth.setText("");
textFieldSouth.requestFocus();
}
});
}
}
}
/*javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
}
}); */
You have literally translated a main-loop structure, which is perfectly suitable for a command line application, to swing. Then you immerse yourself in infinite loops in your main thread looking for a change in shared variables. This conflicts with the way Swing manages things, the main thread of the application is paramount for Swing to manage its repainting and its event handling, and your code is competing against it for the processor. I think we can think of a better design for a Swing application.
You have 2 possibilites:
You can take your original command line program and just replace any reading you take from the keyboard for a modal dialog asking for a letter. This way you respect your sequential design and avoid multi-threading problems.
Or my favorite: I suggest that you consider completely changing your sequential design to a responsive one. In this case, you renounce to a main loop, just show a JPanel inside a JFrame with your UI, and then just write responsive event handlers to each button or change in your inputs. You should just store the state of your program into the main class and your event handlers interact with it.
By the way, whatever your decision, I strongly advise you to remove all that invokeLater(new Runnable() ...), being innecessary and maybe dangerous (you can be introducing race conditions between your event handlers by doing it)
In order to avoid major headaches, you should redesign the control of your application.
Without a GUI, you directly control the process: wait for input, process, show results, repeat.
With a GUI, you show a window and then do nothing. When the user inputs something, the GUI invokes one of your callback methods, and there you react according to your current state.
So: don't try to have a control thread, it's very easy to have a lot of threading problems. Set some variables which tell you what is the current game state (wait for "START" keyword, wait for guess, finished...), and update them when the user does something.
My first post, so forgive any incorrect etiquette. I'm currently doing my year end project for school and I need a bit of help. I am making a GUI java app in Netbeans. I have two classes. One is a class that controls a timer, the other is a class that is a scoreboard screen. I need to update the scoreboard timerLabel with the time that is being counted down in the timerClass. Its quite messy as there is another timer label in the Timer class which does update. My problem is that I cannot get timerLabel in MatchScreen() to update. Here is my code :
Timer Class
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class TimerClass extends JFrame {
Timer timer;
JLabel promptLabel, timerLabel;
int counter;
JTextField tf;
JButton button;
MatchScreen call = null;
public TimerClass() {
call = new MatchScreen();
setLayout(new GridLayout(4, 4, 7, 7));
promptLabel = new JLabel(""
+ "Enter number of seconds for the timer",
SwingConstants.CENTER);
add(promptLabel);
tf = new JTextField(5);
add(tf);
button = new JButton("Start");
add(button);
timerLabel = new JLabel("waiting...",
SwingConstants.CENTER);
add(timerLabel);
event e = new event();
button.addActionListener(e);
System.out.println("Button pressed");
}
public class event implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("Action performed");
int count = (int) (Double.parseDouble(tf.getText()));
timerLabel.setText("Time left: " + count);
call.setTimerLabel(count);
System.out.println("Passed count to tc");
TimeClass tc = new TimeClass(count);
timer = new Timer(1000, tc);
System.out.println("Timer.start");
timer.start();
//throw new UnsupportedOperationException("Not supported yet.");
}
/*public void actionPerformed(ActionEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}*/
}
public class TimeClass implements ActionListener {
int counter;
public TimeClass(int counter) {
this.counter = counter;
}
public void actionPerformed(ActionEvent e) {
counter--;
if (counter >= 1) {
call.setTimerLabel(counter);
} else {
timerLabel.setText("END");
timer.stop();
Toolkit.getDefaultToolkit().beep();
}
}
}
public static void main(String args[]) {
TimerClass gui = new TimerClass();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setSize(250, 150);
gui.setTitle("Time Setup");
gui.setVisible(true);
}
}
And now the ScoreBoard Screen
public class MatchScreen extends javax.swing.JFrame {
int redScore = 0, blueScore = 0, blueCat1 = 0,
blueCat2 = 0, redCat1 = 0, redCat2 = 0, winner = 0;
public MatchScreen() {
initComponents();
}
//Determine Winner of the match
public int getWinner() {
if (redScore > blueScore) {
winner = 1;
} else {
winner = 2;
}
return winner;
}
public void setTimerLabel(int a) {
int time = a;
while (time >= 1) {
timerLabel.setText("" + time);
}
if (time < 1) {
timerLabel.setText("End");
}
}
private void jButton13ActionPerformed(java.awt.event.ActionEvent evt) {
//Creates an object of the timerClass
TimerClass gui = new TimerClass();
gui.setSize(300, 175);
gui.setTitle("Time Setup");
gui.setVisible(true);
}
}
Some code that I felt is irrelevant was left out from the MatchScreen().
Many thanks
Managed to solve the general problem. I put all the code into one class. Not ideal, but it works :/ Anyway, deadlines are looming.
Sincere thanks.
You have a while loop in the setTimerLabel method, which I don't think you intended to put there. Also, you take the parameter a and assign it to time and then never use a again, why not just rename your parameter to time and bypass that additional variable?
EDIT
Sorry, I forgot to explain what I'm seeing :P If you say call.setTimerLabel(10) then you hit that while loop (while(time >= 1) which is essentially running while(10 >= 1) which is an infinite loop. Your program is never leaving the method setTimerLabel the first time you call it with a value >= 1.