Ben Carlisle
Ben Carlisle

Reputation: 11

Use KeyListener in a loop

I don't have a lot of experience with KeyListeners but I used one in my application and it works fine except I need to wait for input before my program can continue. For this I made a while loop that loops until the String temp is not null (which would mean there would be input).

The problem is there is no way to type in the JTextField (called input). Below is code from my two methods that are supposed to work together so that the text in my JTextField (input) can be returned (as temp). I'm not sure why this doesn't work or how to fix it.

The keyPressed method for my KeyListener:

 public void keyPressed(KeyEvent e)
{
    //only sends text if the enter key is pressed
    if (e.getKeyCode()==KeyEvent.VK_ENTER)
    {
        //if there really is text
        if (!input.getText().equals(""))
        {
            //String temp is changed from null to input
            temp=input.getText();
            //text sent to another JTextField
            output.append(temp+"\n");
            //input no longer has text
            input.setText("");
        }
    }
}

The method thats trying to get text, also in my KeyListener class

public String getTemp()
{
    booleans isNull=temp==null; 
    //loops until temp is not null
    while (isNull)
    {
        //unnecessary line of code, only used so the loop not empty
        isNull=checkTemp();
    }   
    return temp;
}
public boolean checkTemp()
{
    return temp==null;
}

Upvotes: 0

Views: 1466

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

Your while loop is a common console program construct, but understand that you're not creating a console program here but rather an event-driven GUI, and in this situation, the while loop fights against the Swing GUI library, and you need to get rid of it. Instead of a while loop with continual polling you now want to respond to events, and if you're listening for user input into a JTextField do not use a KeyListener as this low-level listener can cause unwanted side effects. Instead add a DocumentListener to the JTextField's Document.

Edit: You're listening for the enter key, and so the solution is even easier: add an ActionListener to the JTextField!

e.g.,

input.addActionListener(e -> {
    String text = input.getText().trim();
    if (text.isEmpty()) {
        return;
    }
    output.append(text + "\n");

    input.setText("");
});

More complete example:

import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import javax.swing.*;

public class ChatBox extends JPanel {
    private static final int COLS = 40;
    private JTextField input = new JTextField(COLS);
    private JTextArea output = new JTextArea(20, COLS);
    private JButton submitButton = new JButton("Submit");

    public ChatBox() {
        output.setFocusable(false); // user can't get into output
        JScrollPane scrollPane = new JScrollPane(output);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        ActionListener inputListener = e -> {
            String text = input.getText().trim();
            if (text.isEmpty()) {
                return;
            }
            output.append(text + "\n");

            input.setText("");
            input.requestFocusInWindow();
        };

        input.addActionListener(inputListener);
        submitButton.addActionListener(inputListener);

        JPanel bottomPanel = new JPanel();
        bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
        bottomPanel.add(input);
        bottomPanel.add(submitButton);

        setLayout(new BorderLayout());
        add(scrollPane, BorderLayout.CENTER);
        add(bottomPanel, BorderLayout.PAGE_END);
    }

    private static void createAndShowGui() {
        ChatBox mainPanel = new ChatBox();

        JFrame frame = new JFrame("Chat Box");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

Upvotes: 1

Related Questions