0

I have a GUI that has one output text box and one input text box. I would like, if reasonably attainable, to only use the one input box for all user inputs. I have a situation where I ask the user a question, they input their answer, and then inside the method, I'd like to ask a sub-question using that same input text box. However, in the method I created to handle this interaction, so far I am unable to change the text box or press any keys. How should I fix my code?

EDIT: Taking into account comments stating I should not use Thread.sleep(), I attempted to use a Timer instead. However, now instead of waiting, the method immediately fails and returns "N". Forgive me for being relatively new to GUIs and Swing Timers. What do I need to do to have the program wait while still allowing me to type and press enter?

    public static String pauseUntilKey(JTextField tf)
{
    pause = true;

    tf.removeKeyListener(tf.getKeyListeners()[0]);
    KeyAdapter pauseForInput = new KeyAdapter() { //Get rid of the old keyAdapter and put in the new one just for this function
        @Override
        public void keyPressed(KeyEvent arg0) {
            if(arg0.getKeyCode() == KeyEvent.VK_ENTER) //When the enter key is pressed, this should trigger
            {
                pause = false; //Set local variable pause to be false to let us know we need to stop the while loop
                answer = tf.getText();
                tf.setText("");
            }
        }
    };
    timer = new Timer(1000, new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            if(pause == false)
                timer.stop();
        }
    });
    timer.start();


    KeyAdapter enterMain = new KeyAdapter() { //Put the old key adapter back in
        @Override
        public void keyPressed(KeyEvent arg0) {
            if(arg0.getKeyCode() == KeyEvent.VK_ENTER)
            {
                roster = textInput(tf.getText(), roster, names, true, tf); //Analyze the line using textInput function, update the roster with any changes
                tf.setText("");
            }
        }
    };
    tf.addKeyListener(enterMain);
    if(pause == false) 
        return answer; //If we left the while loop the way I wanted, then return whatever the user wrote before pressing enter.
    return "N"; //Otherwise, just return N for No.
}
  • 1
    * I am unable to change the text box or press any keys* - don't use Thread.sleep(). This prevents the GUI for responding to events. Instead you use a [Swing Timer](https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html). A Timer allows you to schedule an event after a certain time period. So you start the Timer when you ask the question and then perform so activity if the timer fires. When the user responds you can stop the timer. – camickr Nov 06 '19 at 16:58
  • With respect to your recommendation, I got rid of Thread.sleep(). However, now I am struggling with Timer instantly failing and the method returning "N". Am I not implementing Timer correctly? – Tyler Clark Nov 06 '19 at 21:55
  • 1
    *What do I need to do to have the program wait* - this is how event driven programming works. The program just sits there and does nothing. It only does something when you generate an event, for example, by using the mouse or typing with the keyboard. Then if you have added listeners, the listener code is executed. You don't need any Boolean variable when using a Timer. Also you should not be using a KeyListener to listen for the Enter key. Instead, you add an ActionListener to the text field. The ActionListener will be invoked when the Enter key is pressed. – camickr Nov 06 '19 at 22:30
  • 1
    *I'd like to ask a sub-question using that same input text box.* - so when the logic in your application asks the question you start the Timer. If the Timer fires, then it means the user did not enter the text in the desired time interval, so you do your error process (whatever that is). In your ActionListener you "stop" the Timer. This will prevent the Timer from doing the error processing and you do your regular processing, whatever that it. Check out: https://stackoverflow.com/a/7816604/131872 for a basic example. – camickr Nov 06 '19 at 22:36

1 Answers1

0

The variable pause need to be declared volatile, otherwise the worker thread will never be notified by the changes done in the Event Dispatcher Thread (that will call the keyPressed method).

Also, if you have not already done so, you need to use a SwingWorker instance that will call the pauseUntilKey, otherwise you lock up the entire swing subsystem since it is single-threaded.