KeyListener
s are NEVER appropriate solutions to use with text components, if you want to be notified when a text component changes, you use a DocumentListener
, if you want to change/filter what can be entered into a text component, you use a DocumentFilter
, if you need to change a special key, like Enter, you should use a key binding
See How to Use Key Bindings for more details.
One of the problems you could have with KeyListener
is not knowing when the key stroke is processed by the text component, in your case, it may not be a major issue, but it could change the way the program works on different platforms.
Instead, you can override the JTextArea
's key binding for the Enter key (named insert-break
). This provides you with the ability to actually change the behavior of the key stroke, or, in your case, manage how you process the event. For example, this replaces the Action
for the text area's Enter key, but retains the previous/default behavior...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class KeyBindingsTest {
public static void main(String[] args) {
new KeyBindingsTest();
}
public KeyBindingsTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
public TestPane() {
ta = new JTextArea(10, 20);
ActionMap am = ta.getActionMap();
Action proxy = am.get("insert-break");
am.put("insert-break", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
// You can process the event through the original action BEFORE
// you do your own processing
//proxy.actionPerformed(e);
System.out.println("You pressed the enter key, you can have candy");
// Or you can process the event through the original action AFTER
// you do your own processing, you have now gained control
proxy.actionPerformed(e);
}
});
setLayout(new BorderLayout());
add(ta);
}
}
}
Now, you could even go to the extent for creating your own JTextArea
which supported ActionPerformed
...
public class ActionableTextArea extends JTextArea {
private String actionCommand;
public ActionableTextArea() {
installKeyBindings();
}
public ActionableTextArea(String text) {
super(text);
installKeyBindings();
}
public ActionableTextArea(int rows, int columns) {
super(rows, columns);
installKeyBindings();
}
public ActionableTextArea(String text, int rows, int columns) {
super(text, rows, columns);
installKeyBindings();
}
public ActionableTextArea(Document doc) {
super(doc);
installKeyBindings();
}
public ActionableTextArea(Document doc, String text, int rows, int columns) {
super(doc, text, rows, columns);
installKeyBindings();
}
protected void installKeyBindings() {
ActionMap am = getActionMap();
Action proxy = am.get("insert-break");
am.put("insert-break", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
// You can process the event through the original action BEFORE
// you do your own processing
//proxy.actionPerformed(e);
fireActionPerformed();
// Or you can process the event through the original action AFTER
// you do your own processing, you have now gained control
proxy.actionPerformed(e);
}
});
}
public void addActionListener(ActionListener listener) {
listenerList.add(ActionListener.class, listener);
}
public void removeActionListener(ActionListener listener) {
listenerList.remove(ActionListener.class, listener);
}
public void setActionCommand(String actionCommand) {
this.actionCommand = actionCommand;
}
public String getActionCommand() {
return actionCommand;
}
protected void fireActionPerformed() {
ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
if (listeners.length > 0) {
ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, getActionCommand());
for (ActionListener listener : listeners) {
listener.actionPerformed(evt);
}
}
}
}