According to Java concurrency bible 'Java concurrency in practice'
... Timer has some drawbacks, and ScheduledThreadPoolExecutor should be thought of as its replacement.
Thus, I would do something like this example:
public class DelayedSearch extends JFrame {
public DelayedSearch() {
final JPanel panel = new JPanel(new BorderLayout());
final JTextField field = new JTextField(30);
panel.add(field, BorderLayout.NORTH);
final JLabel status = new JLabel(" ");
panel.add(status, BorderLayout.SOUTH);
this.add(panel);
this.pack();
final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
field.addKeyListener(new KeyAdapter() {
private ScheduledFuture<?> scheduled;
@Override
public void keyTyped(KeyEvent e) {
if (scheduled != null) scheduled.cancel(false);
scheduled = executor.schedule(new Runnable() {
@Override
public void run() { // Perform search here. Just set status for demo.
status.setText("Search: " + field.getText());
}
}, 1, TimeUnit.SECONDS);
}
});
}
public static void main(String[] args) {
new DelayedSearch().setVisible(true);
}
}
Note: I'm updating the status from a thread other than the EDT here which is illegal, but you get the idea.
EDIT: based upon great comments below (thanks!) Timer
will work in this simple case, and it makes it easy to use a daemon thread (although it does have problems with tasks that throw exceptions, as described in the book). To do this replace above executor and listener as follows:
...
final Timer timer = new Timer(true); // use daemon thread.
field.addKeyListener(new KeyAdapter() {
private TimerTask task;
@Override
public void keyTyped(KeyEvent e) {
if(task != null)task.cancel();
task = new TimerTask() {
@Override
public void run() {
status.setText("Search: " + field.getText());
}
};
timer.schedule(task, 1000);
}
});