Reputation: 5
I am developing a Swing application, in which I want enter key work as tab key for all component of JFrame
except JButton
components and dialog boxes. For that I have set ENTER and TAB as default focus traversal keys.
KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
KeyStroke tab = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
Set<KeyStroke> keys = new HashSet<>();
keys.add(enter);
keys.add(tab);
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, keys);
This is working well,but I want that ENTER Key work as Action on JButton
and Dialog Boxes.
Upvotes: 0
Views: 607
Reputation: 26
The approved answer is actually bit wrong.
It add Enter as focus travel key, however it DOES NOT modify the basic button behavior of .doClick();
So this code spams .doClick();
second time. I came across this issue when on button action I was writing data from bunch of text Fields to table, and it added the same record two times. solution for this is pretty simple, on instanceof JButton
just make return;
repaired code upgraded to java 14 instanceof
private static class AWTListener implements AWTEventListener{
@Override
public void eventDispatched(AWTEvent event) {
if (event instanceof KeyEvent key && key.getKeyCode() == KeyEvent.VK_ENTER && key.getModifiersEx() == 0 && key.getID() == KeyEvent.KEY_PRESSED) {
if (key.getComponent() instanceof JButton) {
return;
}
key.getComponent().transferFocus();
}
}
}
Upvotes: 0
Reputation: 797
I think even the solution using AWTEventListener would work, I would suggest avoid using AWTEventListener if another solution is available. It is because it's so powerful that it intercepts all kinds of events globally before they reach their real targets, so if anything went wrong (such as a NullPointerException) in the middle, the whole application would stop working.
My proposed solution makes use of input map & action map which adds handling of Enter key to any focused component in a particular container.
The advantage:
The disadvantage:
Here is the sample program:
public MainFrame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500, 500);
setLayout(new GridLayout(2, 2));
addAllComponents();
addEnterKeyAsFocusTraversal();
}
private void addAllComponents() {
add(new JTextField());
add(new JTextField());
add(new JButton("OK"));
add(new JButton("Cancel"));
}
private void addEnterKeyAsFocusTraversal() {
final String ENTER_KEY_ACTION = "EnterKeyAction";
// Here uses the content pane of type Container so a cast is required,
// in other case it could be the root container which may already be an instance of JComponent.
JComponent contentPane = (JComponent) getContentPane();
contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), ENTER_KEY_ACTION);
contentPane.getActionMap().put(ENTER_KEY_ACTION, createEnterKeyAction());
}
private AbstractAction createEnterKeyAction() {
return new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if (focusOwner != null) {
if (focusOwner instanceof AbstractButton) {
((AbstractButton) focusOwner).doClick();
} else {
focusOwner.transferFocus();
}
}
}
};
}
Upvotes: 0
Reputation: 11327
It's possible, but using another way: global event listener. To register a global event listener you should use the Toolkit
class:
Toolkit.getDefaultToolkit().addAWTEventListener(listener, mask);
Here is an example for your case:
import java.awt.AWTEvent;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class FocusTransferTest {
public static void main(String[] args) {
JFrame frm = new JFrame("Test focus transfer");
JPanel panel = new JPanel();
panel.add(new JTextField(10));
panel.add(new JTextField(10));
panel.add(new JTextField(10));
JButton btn = new JButton("Press me");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frm, "It's a message", "Info",
JOptionPane.INFORMATION_MESSAGE);
}
});
panel.add(btn);
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEnterKeyListener(),
AWTEvent.KEY_EVENT_MASK);
frm.add(panel);
frm.pack();
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
private static class AWTEnterKeyListener implements AWTEventListener {
@Override
public void eventDispatched(AWTEvent event) {
if (event instanceof KeyEvent) {
KeyEvent key = (KeyEvent) event;
if (key.getKeyCode() == KeyEvent.VK_ENTER && key.getModifiersEx() == 0
&& key.getID() == KeyEvent.KEY_PRESSED) {
if (key.getComponent() instanceof AbstractButton) {
((AbstractButton) key.getComponent()).doClick();
} else {
key.getComponent().transferFocus();
}
}
}
}
}
}
Upvotes: 1