Handling abstract action in a JTextField - java

I have a JTextField that has an abstract action, which tests to see when I type in the enter key:
static Action action = new AbstractAction(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("done");
textWindow.append(textInput.getText());
inputEarly = textInput.getText();
hasInput = true;
textInput.setText("");
}
};
And I have a while loop which is waiting to see if the enter key has been pressed, by waiting until the variable hasInput = true, however every time the enter key is pressed and the action works, I know this because I have it print out "done" in the console, it never breaks from the while(true) loop that I have got running below it:
while(true) {
textWindow.append("localhost " + getDateTime() + " > ");
while(true) {
if(hasInput) {
System.out.println("works");
input = inputEarly;
hasInput = false;
break;
}
}
hasInput is declared:
public class Main_Menu extends JFrame{
static Boolean hasInput = false;
Is there a reason why it won't work?

Related

Trouble determining how to make my calculator calculate properly

This is probably the nth time you've received a newbie question regarding calculators, but I just can't figure it out, been working on it for two to three days. The way I have built my calculator at the moment does not suffice and I know I have to start calculating at the time I press the '=' button, but I simply can't figure out how to do so. Due to this reason I have reverted back to my original calculator code, in which it calculates when I press an operation button (like '+') which didn't work, but I was hoping that that would allow me to properly build on it. Here's the code:
package rekenmachine;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.*;
public class Rekenmachine extends JFrame
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(300,500);
frame.setLocation(800,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Rekenmachine");
RekenPaneel rekenpaneel = new RekenPaneel();
frame.setContentPane(rekenpaneel);
frame.setVisible(true);
}
private static int getal, totaalGetal;
private boolean optellen, aftrekken, vermenigvuldigen, delen;
public int Optellen(int getal)
{
reset();
optellen = true;
totaalGetal += getal;
getal = 0;
return totaalGetal;
}
public int Aftrekken(int getal)
{
reset();
aftrekken = true;
totaalGetal -= getal;
getal = 0;
return totaalGetal;
}
public int Delen(int getal)
{
reset();
delen = true;
totaalGetal /= getal;
getal = 0;
return totaalGetal;
}
public int Vermenigvuldigen(int getal)
{
reset();
vermenigvuldigen = true;
totaalGetal *= getal;
getal = 0;
return totaalGetal;
}
public int getGetal()
{
return getal;
}
public int getTotaalGetal()
{
return totaalGetal;
}
public void reset()
{
optellen = false;
aftrekken = false;
delen = false;
vermenigvuldigen = false;
getal = 0;
totaalGetal = 0;
}
}
class RekenPaneel extends JPanel
{
JButton knop0, knop1, knop2, knop3, knop4, knop5, knop6, knop7, knop8, knop9,
knopOptel, knopAftrek, knopVermenigvuldigen, knopDelen, knopUitkomst,
knopWissen;
JTextField invoerVak;
JPanel textPaneel, knopPaneel, logoPaneel;
Rekenmachine rekenmachine;
public RekenPaneel()
{
rekenmachine = new Rekenmachine();
setLayout(new BorderLayout());
textPaneel = new JPanel();
knopPaneel = new JPanel();
logoPaneel = new JPanel();
textPaneel.setLayout(new FlowLayout());
knopPaneel.setLayout(new GridLayout(4,4));
logoPaneel.setLayout(new FlowLayout());
Border rand = BorderFactory.createEmptyBorder(10, 10, 10, 10);
knop0 = new JButton("0");
knop0.addActionListener(new knop0Handler());
knop1 = new JButton("1");
knop1.addActionListener(new knop1Handler());
knop2 = new JButton("2");
knop2.addActionListener(new knop2Handler());
knop3 = new JButton("3");
knop3.addActionListener(new knop3Handler());
knop4 = new JButton("4");
knop4.addActionListener(new knop4Handler());
knop5 = new JButton("5");
knop5.addActionListener(new knop5Handler());
knop6 = new JButton("6");
knop6.addActionListener(new knop6Handler());
knop7 = new JButton("7");
knop7.addActionListener(new knop7Handler());
knop8 = new JButton("8");
knop8.addActionListener(new knop8Handler());
knop9 = new JButton("9");
knop9.addActionListener(new knop9Handler());
knopOptel = new JButton("+");
knopOptel.addActionListener(new knopOptelHandler());
knopAftrek = new JButton("-");
knopAftrek.addActionListener(new knopAftrekHandler());
knopVermenigvuldigen = new JButton("*");
knopVermenigvuldigen.addActionListener(new knopVermenigvuldigenHandler());
knopDelen = new JButton("/");
knopDelen.addActionListener(new knopDelenHandler());
knopUitkomst = new JButton("=");
knopUitkomst.addActionListener(new knopUitkomstHandler());
knopWissen = new JButton("C");
knopWissen.addActionListener(new knopWissenHandler());
invoerVak = new JTextField(25);
invoerVak.setHorizontalAlignment(invoerVak.RIGHT);
invoerVak.setEditable(false);
invoerVak.setBackground(Color.WHITE);
textPaneel.add(invoerVak);
knopPaneel.add(knop7);
knopPaneel.add(knop8);
knopPaneel.add(knop9);
knopPaneel.add(knopDelen);
knopPaneel.add(knop4);
knopPaneel.add(knop5);
knopPaneel.add(knop6);
knopPaneel.add(knopVermenigvuldigen);
knopPaneel.add(knop1);
knopPaneel.add(knop2);
knopPaneel.add(knop3);
knopPaneel.add(knopOptel);
knopPaneel.add(knop0);
knopPaneel.add(knopWissen);
knopPaneel.add(knopUitkomst);
knopPaneel.add(knopAftrek);
add(textPaneel, BorderLayout.NORTH);
add(knopPaneel, BorderLayout.CENTER);
add(logoPaneel, BorderLayout.SOUTH);
}
class knop0Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "0");
}
}
class knop1Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "1");
}
}
class knop2Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "2");
}
}
class knop3Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "3");
}
}
class knop4Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "4");
}
}
class knop5Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "5");
}
}
class knop6Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "6");
}
}
class knop7Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "7");
}
}
class knop8Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "8");
}
}
class knop9Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText(invoerVak.getText() + "9");
}
}
class knopOptelHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Optellen(invoerGetal);
invoerVak.setText("");
}
}
class knopAftrekHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Aftrekken(invoerGetal);
invoerVak.setText("");
}
}
class knopVermenigvuldigenHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Vermenigvuldigen(invoerGetal);
invoerVak.setText("");
}
}
class knopDelenHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Delen(invoerGetal);
invoerVak.setText("");
}
}
class knopUitkomstHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
invoerVak.setText("" + rekenmachine.getTotaalGetal());
rekenmachine.reset();
}
}
class knopWissenHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
rekenmachine.reset();
invoerVak.setText("");
}
}
}
What it basically does is look like a calculator, all buttons work, yet the way it calculates is way off, if at all. I think what I need to do is save a number, when I press + it should add the next number, if I press - it should substract the next number, if I press * it should multiply by the next number and if I press / it should divide by the next number, then when I press = it should show the result, yet I have no idea how to do that.
Should it be done with an arraylist? If so, how could I properly save the result? I mean, using it with two numbers isn't that hard, you just save two numbers and do something with them, then show the result, but a person doesn't always use just two numbers.
To explain the problem I'm having more clearly: for example, when I enter '50' and then press '+' it SHOULD convert "50" to getal = 50 and start the Optellen method, then totaalGetal should become 50, it then empties the textfield. If I then add '3', it should say 53 when I press '=' yet it still shows 50 if I'm lucky. To solve that I assume I have to make the calculation WHEN I press '=' but I don't know how to save/calculate numbers before having done that.
Can anybody tell me what to do before I've lost all my hair? :P
When you click on the +, you're calling this:
knopOptel.addActionListener((ActionEvent e) ->
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.addition(invoerGetal);
invoerVak.setText("");
});
But when you click on +, you're not doing the calculation yet! What you should be doing is:
The user type a number
The user click on + (for example)
In your ActionListener, you read the number on the screen, you store it in getal, you clear the screen, and you set your boolean optel to true
The user types another number
The user click on equal
In your equal Listener, you read the number you read the number on the screen, and depending on the flag (optel in the example), you calculate the result
you display the result
So indeed, the calculation is done when you press equal.
A small code example:
knopOptel.addActionListener((ActionEvent e) ->
{
int invoerGetal = Integer.parseInt(invoerVak.getText()); // get the number
calculate(invoerGetal); //sets totalNumber to what it should be by looking at the flags
invoerVak.setText(totalNumber); // we write the temporary result
additionFlag = true; // next number must be added
});
And your calculate function should just be something like:
private void calculate(int aInvoerGetal) {
if (addition)
totalNumber += aInvoerGetal;
else if (substract)
totalNumber -= aInvoerGetal;
else if (divide)
totalNumber /= aInvoerGetal;
else if (multiply)
totalNumber *= aInvoerGetal;
resetFlags();
}
TO GO FURTHER:
Now, if you want to support multiple caculations (5+5+5+3), it's easy. When you click on +, -, *, /, you first call the equalActionListener.
This way, you get this kind of sequence:
5, + // ==> equal called ==> 5 (because the flags are all false) ==> flag + to true
10, + // ==> equal called ==> 15 because 5 in memory and + flag was on. + flag goes off, then on again (because you pressed + again)
4, = // ==> equal called ==> 19
When developing something, you have to think first how you want to solve a problem. Work from there by designing a solution. If you have a programmable solution, implement it. The UI may come later. That's a core skill that a developer should have.
1) You want to have a calculator that support +, -, / and *. The output should be shown if "=" is clicked.
2) Think with classes. That concept may be new for you, but you will discover later from. Your main class that does the calculations is Rekenmachine. (From a design perspective, it should be a stand alone class, but that's not important now). You need to separate it from your UI layer.
Your class supports the actions that you have implemented with the UI. That's good. But I also see things that shouldn't be there
public int Vermenigvuldigen(int getal)
{
reset(); // reset the calculator ?
vermenigvuldigen = true; // purpose ?
totaalGetal *= getal;
getal = 0; // resetting argument getal ?
return totaalGetal;
}
Here, I'm not sure why you're calling reset() because what it does is
public void reset()
{
optellen = false;
aftrekken = false;
delen = false;
vermenigvuldigen = false;
getal = 0;
totaalGetal = 0;
}
When reading the above method, you see that it resets the value that you tried to add on. Of course your calculation would go wrong because you're erasing previous data... resetting everything back to initial state. I also don't understand the setting to "true" or "false" on the actions. Perhaps for the UI? That is not required.
Make it simple:
When creating Rekenmachine, set the variable totaalGetal to 0 as default. That variable holds the value of your calculations performed so far. That's the start. When you have an addition, use
public void add(int getal) {
totaalGetal+= getal; // means totaalGetal = totaalGetal + getal.
}
Before calling add() you have to parse the string to an integer. This can be done in the button action:
class knop1Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
// get input
String input = invoerVak.getText();
// convert
int converted = convertToInt(input);
// instruct myRekenmachine to add the value
myRekenmachine.add(converted);
}
}
Important note ... use concise naming ... "knop1handler" is difficult to read. Use "addButtonHandler" to indicate that this class handles the add button.
convertToInt is a method that reads in a String and returns with an integer. You have to implement that yourself. myRekenmachine is an instance of your Rekenmachine class.
This above is for addition. Implement the same for other operands. If you want to adjust the UI, do that in the handler.
Now, when you press =, just return the totaalGetal value.
PS: Not sure, but ask if you are allowed to write names in English. My native language is Dutch, but during my CS courses, I am allowed to program completely in English. Please try to ask it because English is the main language in IT world if you're aiming for a career in IT.
Wesley, did you think about what you wanted the calculator to do before you started coding? e.g. would it support brackets, sin/cos, memory. Did you think about how logically these functions would work and then think of how they could be implemented in Java? A few flow charts and some pesudocode can go a long way when you're starting out in a new language if only to help you comprehend what it is you are trying to do.
BTW I know it's tempting to start with the GUI code and move into the logic of the application but it is usually better to start with the logic and then move onto the GUI. You can hard code the values for inputs and see if the functionaly behaves as expected and then introduce parameters with values passed in from else where.
EDIT
I think I know why your + key is not working. The reset() method is setting getal and totalGetal to 0 before adding them. 0 + 0 is 0.
knopOptel = new JButton("+");
knopOptel.addActionListener(new knopOptelHandler());
class knopOptelHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String invoer = invoerVak.getText();
int invoerGetal = Integer.parseInt(invoer);
rekenmachine.Optellen(invoerGetal);
invoerVak.setText("");
}
}
public int Optellen(int getal)
{
reset();
public void reset()
{
optellen = false;
aftrekken = false;
delen = false;
vermenigvuldigen = false;
getal = 0;
totaalGetal = 0;
}
optellen = true;
totaalGetal += getal;
getal = 0;
return totaalGetal;
}

Swing threading issue?

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.

Why does this method get called twice when button is clicked?

I am building a simple applet and in my applet I have a combo box with a drop down list. When an option is selected, and a button "add" is clicked, the selection is take and pass to a method that creates an object. The only problem is that when I click the button, it adds the object fine, but then when I try adding another slelection, it deletes the previous one and sets the new one equal to the same attributes as the new one. So in essence it is re adding the selection.
btnAdd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addTooObj(comboBox.getSelectedItem().toString(), lblStatusLabel);
System.out.println(comboBox.getSelectedIndex());
}
});
private void addToobj(String num,JLabel j){
System.out.println(num);
Object objToBeAdded = null;
long objNumber = Long.parseLong(num);
int quan = 0;
if (objNumber == 12354589621l) {
objToBeAdded = new Item(objNumber, 2.00, quan);
} else if (objNumber == 21) {
objToBeAdded = new Item(objNumber, 1.50, quan);
} else if (objNumber == 12) {
objToBeAdded = new Item(objNumber, 5.20, quan);
} else {
System.out.println("error");
}
oldObj.add(objToBeAdded);
}
Within your actionPerformed method, you could get the action command and review what actions it is been fired for and then only call your method if the action is the action you want.
public void actionPerformed(ActionEvent e) {
String action = e.getActionCommand();
System.out.println("The action was: " + action);
if(action.equals("What ever action you want")){
addTooObj(comboBox.getSelectedItem().toString(), lblStatusLabel);
System.out.println(comboBox.getSelectedIndex());
}
}

showMessageDialog() gets called for two times in FocusListener

I have 2 textfields in a JFrame and I want to validate the data in textfield1 when the focus gets lost from textfield1. So I have used FocusListener and used showMessageDialog() in the FocusLost() method and that then sets back the focus back to textfield1. It works fine when I click on any component inside the JFrame window other than textfield1,but when I click anywhere outside the JFrame window, the showMessageDialog() gets called two times and the focus goes to textfield2 whereas the focus should remain on textfield1.
#Override
public void focusGained(FocusEvent e) {}
#Override
public void focusLost(FocusEvent e) {
boolean show = false;
String theRegex = "[0-9]";
Pattern checkRegex = Pattern.compile(theRegex);
Matcher regexMatcher = checkRegex.matcher( MemberID );
while ( !regexMatcher.find() && show==false){
JOptionPane.showMessageDialog(null,"Please enter numbers","Validation Error",JOptionPane.ERROR_MESSAGE);
MemberID_Text.requestFocusInWindow();
MemberID_Text.selectAll();
show = true;
}
}
you can do this to verify if a number is entered, and avoid regex all together
class IntVerifier extends InputVerifier {
#Override public boolean verify(JComponent input) {
String text =((JTextField) input).getText();
int n = 0;
try {
n = Integer.parseInt(text); }
catch (NumberFormatException e) {
return false;
}
return true;
}
}
then use the input verifier on the text field
IntVerifier intv = new IntVerifier();
myTextField = new JTextField();
myTextField.setInputVerifier(intv);

JTextArea new line on shift + enter

I've added a keylistener to my JTextArea field, but it doesn't behave as I expected.
inputTextArea.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent k) {
//If the return button is hit, only set to a new line if shift is also down.
if(k.getKeyChar() == KeyEvent.VK_ENTER) {
if(k.isShiftDown()) {
inputTextArea.append(" \n");
} else {
//Send The Message...
boolean cleanTextField = false;
try {
sendMessage(inputTextArea.getText());
cleanTextField = true;
msgScrollPane.setAutoscrolls(true);
JScrollBar vbar = msgScrollPane.getVerticalScrollBar();
if ((vbar.getValue() + vbar.getVisibleAmount()) == vbar.getMaximum()) {
msgPane.setCaretPosition(msgDoc.getLength());
}
} catch (Exception ex) {
ex.printStackTrace();
cleanTextField = false;
} finally {
if(cleanTextField) {
inputTextArea.setText("");
}
}
}
}
}
});
I want this:
- If the return button is hit and shift is down: add a new line.
- If the return button is hit and the shift button isn't down: no new line, but submit.
Now it behaves like this:
- If I hit the return button and shift is down: no line added. Nothing happens.
- If I hit the return button and shift isn't down: submitted, but if I start typing again it begins on new line.
Does someone know how to do what I want?
EDIT:
I tried some other code to detect if the shift button is down:
if((k.getModifiersEx() == KeyEvent.SHIFT_DOWN_MASK) ||
(k.getModifiers() == KeyEvent.SHIFT_DOWN_MASK)) {
This doesn't work as well
You may use the InputMap and ActionMap of the JTextArea to map the key strokes to actions:
private static final String TEXT_SUBMIT = "text-submit";
private static final String INSERT_BREAK = "insert-break";
...
private void initialize() {
InputMap input = inputTextArea.getInputMap();
KeyStroke enter = KeyStroke.getKeyStroke("ENTER");
KeyStroke shiftEnter = KeyStroke.getKeyStroke("shift ENTER");
input.put(shiftEnter, INSERT_BREAK); // input.get(enter)) = "insert-break"
input.put(enter, TEXT_SUBMIT);
ActionMap actions = inputTextArea.getActionMap();
actions.put(TEXT_SUBMIT, new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
submitText();
}
});
}
...
private void submitText() {
// TODO
}
The original action for ENTER - "insert-break" - is used for shift ENTER.
Try using keyTyped and not keyPressed. I beleive keyPressed gives you an event for the shift and for the enter, whereas keyTyped gives you one combined event with a modifier.
Instead of doing the actions immediately on receiving the event, sequence them for later by posting them using SwingUtilities.invokeLater(). The code should look like:
if(k.isShiftDown()) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
inputTextArea.append(" \n");
}
});
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//rest of the else body here
}
});
}
In my opinion, the problems seen here are because application-defined actions and internal actions are not being properly sequenced, leading to repaints happening before the text has been modified.

Categories