newbie
newbie

Reputation: 107

keylistener wait for input

I want to write a live search using Swing components. I am using a keyListener to keep track of the input. Basically i dont want the keyListener to take action every time a button is pressed but instead wait (for some period of time) for more incoming input. This period of time is refreshed every time a button is pressed and the input gets evaluated when it eventually times out (e.g. no button is being pressed within the period meaning that the input is complete). How do I implement that into my keyListener?

Code snippet of main method:

static JTextField nameTextField = new JTextField();

public static void main(String args[]) throws Exception {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    frame.add(nameTextField, BorderLayout.NORTH);

    nameTextField.addKeyListener(new KeyListener() {

        public void keyTyped(KeyEvent keyEvent) {
            //
        }

        @Override
        public void keyPressed(KeyEvent e) {
            //
        }

        @Override
        public void keyReleased(KeyEvent e) {
                   if(waitForMoreInput(50)) {
                       doSomething(nameTextField.getText());
                   }
                }
            }
        }
    }
    );


    frame.setSize(250, 100);
    frame.setVisible(true);
}

Thanks in advance

Upvotes: 1

Views: 1352

Answers (3)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

Much better is for you to use a DocumentListener or DocumentFilter, depending on if you want to listen before or after text has been fully registered with the text component.

The DocumentListener will register any time the text has changed, be it via a key press, via a copy and paste, via a deletion of text. The Timer will then wait however long you wish to do whatever action is required on the text. For example:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

public class DocListenerFoo extends JPanel {
    private JTextField nameTextField = new JTextField(20);

    public DocListenerFoo() {
        add(new JLabel("Add Text:"));
        add(nameTextField);

        int timerDelay = 1000; // one second
        nameTextField.getDocument().addDocumentListener(new MyDocListener(timerDelay));
    }

    private class MyDocListener implements DocumentListener {
        private Timer docTimer;
        private int timerDelay;

        public MyDocListener(int timerDelay) {
            this.timerDelay = timerDelay;
        }

        @Override
        public void changedUpdate(DocumentEvent e) {
            textChangedAction(e);
        }

        @Override
        public void insertUpdate(DocumentEvent e) {
            textChangedAction(e);
        }

        @Override
        public void removeUpdate(DocumentEvent e) {
            textChangedAction(e);
        }

        private void textChangedAction(DocumentEvent e) {
            Document doc = e.getDocument();
            try {
                String text = doc.getText(0, doc.getLength());
                if (docTimer != null && docTimer.isRunning()) {
                    docTimer.stop();
                }

                docTimer = new Timer(timerDelay, new TimerListener(text));
                docTimer.setRepeats(false);
                docTimer.start();
            } catch (BadLocationException e1) {
                e1.printStackTrace();
            }
        }

    }

    private class TimerListener implements ActionListener {

        private String text;

        public TimerListener(String text) {
            this.text = text;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO do check on text here 
            System.out.println("Checking text here: " + text);
        }

    }

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

        JFrame frame = new JFrame("DocListenerFoo");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}

Upvotes: 5

SteakOverflow
SteakOverflow

Reputation: 2033

Don't wait inside the key or document event, it just blocks the program from being processed further. Instead save the current time or (re)start a timer in the event and execute your action later somewhere else.

Upvotes: 1

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

I'm guessing that you're trying to use a KeyListener with a Swing text component such as a JTextField (I have to guess since you don't tell or show us). If so, then the best solution is don't. Using a KeyListener with these components can mess up the functionality of the components. Much better is for you to use a DocumentListener or DocumentFilter, depending on if you want to listen before or after text has been fully registered with the text component.

For a better more complete answer, post a better more complete question, including your minimal code example and details about your problem.

Upvotes: 0

Related Questions