1

I'm writing a text based adventure game and I ran into a problem. I'm porting it over from terminal to JFrame GUI and I need it to wait for user input before proceeding. I set up a system where there is a boolean variable called buttonPressed which starts out as false. When the submit text button is pressed it changes it to true. There is a while loop that waits for the button to become true before it allows the program to continue, essentially pausing the program until the user submits input. The problem is this only works when I have inside the while loop a system.out.println line written in. Otherwise it doesn't continue after I click the button. What's the problem?

public class event implements ActionListener{
    public void actionPerformed(ActionEvent e){
        moves += 1;
        movesLabel.setText("Moves: " + moves);

        buttonPressed = true;

        try{
            input = (String)(textfield.getText());
            textfield.setText("");

        }catch(Exception ex){
            textfield.setText("Error");
        }
    }
}


public static void main (String args[]) {
    Main gui = new Main();
    gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    gui.setVisible(true);
    gui.setSize(650, 350);
    gui.setTitle("Sprinkles Text Adventure");

    setInventory();

    textArea.setText(textDisplay("Welcome Adventurer!"));
    textArea.setText(textDisplay("What is thy name: "));

    while(!buttonPressed){
      // this only works when I have system.out.println("something") written in
    }

    buttonPressed = false;

    textArea.setText(textDisplay(input));

    if ("alice".equals(input)||"Alice".equals(input)){
        textArea.setText(textDisplay("Stop toking the magical pipe, "));
        textArea.setText(textDisplay("you aren't alice and this isn't wonderland"));
        textArea.setText(textDisplay("Now down the rabbit hole you go!"));
    }
    else if ("l3ikezI".equals(input)||"l3ikezi".equals(input)){
        System.out.println("Magic and Technology flows through your veins");
        System.out.println("Welcome back, Master");
        for(int j = 0; j<14; j++){
            Chest[j]=1;
        }
    }
    else{
        System.out.println("Enter " + input + " and good luck!\n\n");
    }
  • Have you defined `buttonPressed`? – Nick Apr 06 '16 at 20:26
  • yes, on top i initialize it with private static boolean buttonPressed = false; It's weird because it works when I have that one line of code in – Winter Jade Apr 06 '16 at 20:26
  • Then I would guess that the JVM skips empty infinite loops. Maybe you could use Thread.sleep(15) ? – Demurgos Apr 06 '16 at 20:27
  • `buttonPressed` definition is missing... Looks like you have two of them? Hard to say with incomplete code. – hyde Apr 06 '16 at 20:37
  • Could you provide more code? How do you attach ActionListener to the button? – Wojciech Wirzbicki Apr 06 '16 at 20:37
  • I would start by having a look at [Concurrency in Java](http://docs.oracle.com/javase/tutorial/essential/concurrency/). I would also have a look at [How to Make Dialogs](http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html) which will solve your basic problem – MadProgrammer Apr 07 '16 at 00:16

2 Answers2

2

Im no java expert but...
It looks like you are not giving your gui thread time to do anything, since you are busy waiting for your boolean to change. To solve this you should probably use a semaphore. Or, the easier (dirty) solution, call a sleep() in your while loop. For java specific things, look at this question.

On second thought, I found that java has a volatile keyword. I don't know if buttonPressed is declared volatile, but if it is not, the compiler might decide that, since the while-loop is empty, its value is never going to changes, and replaces it by while(true) as an optimisation.

Community
  • 1
  • 1
David van rijn
  • 2,108
  • 9
  • 21
1

This...

while(!buttonPressed){
  // this only works when I have system.out.println("something") written in
}

is just asking for trouble, apart from the fact that you can't guarantee what thread main is actually called in, which could result in you blocking the Event Dispatching Thread, it's just the wrong approach.

Instead of using a JFrame, you want to use a modal JDialog of some kind, which will block the code's execution at the point the dialog is made visible until it is disposed/closed and which does it in safe manner so you can use it within the context of the EDT.

Take a look at Initial Threads, Concurrency in Swing and How to Make Dialogs for more details.

As a general piece of advice, avoid extending directly from top level containers like JFrame and JDialog and instead opt of using something like JPanel, it frees you up and increases the reusability of your components

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366