对于除 JButton 之外的每个组件,Enter 键都用作 Tab 键
Enter Key work as Tab Key for every component except JButton
我正在开发一个 Swing 应用程序,我想在其中输入键作为 JFrame
所有组件的 Tab 键,除了 JButton
组件和对话框。为此,我将 ENTER 和 TAB 设置为默认的焦点遍历键。
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);
这很好用,但是 我希望 ENTER 键作为 JButton
和对话框 上的操作。
这是可能的,但使用另一种方式:全局事件侦听器。要注册全局事件侦听器,您应该使用 Toolkit
class:
Toolkit.getDefaultToolkit().addAWTEventListener(listener, mask);
以下是您的案例示例:
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();
}
}
}
}
}
}
我认为即使使用 AWTEventListener 的解决方案也可行,如果有其他解决方案可用,我建议避免使用 AWTEventListener。正是因为它的强大,在各种事件到达真正的目标之前,它会在全局范围内拦截它们,所以如果中间出现任何问题(例如 NullPointerException),整个应用程序将停止工作。
我提出的解决方案利用了输入映射和操作映射,它们将对 Enter 键的处理添加到特定容器中的任何聚焦组件。
优势:
- 更安全,因为它只影响容器中的组件,而不是所有组件。
缺点:
- 相同的处理代码必须应用于需要此行为的所有容器,但这可以通过静态实用程序方法轻松完成。
示例程序如下:
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();
}
}
}
};
}
我正在开发一个 Swing 应用程序,我想在其中输入键作为 JFrame
所有组件的 Tab 键,除了 JButton
组件和对话框。为此,我将 ENTER 和 TAB 设置为默认的焦点遍历键。
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);
这很好用,但是 我希望 ENTER 键作为 JButton
和对话框 上的操作。
这是可能的,但使用另一种方式:全局事件侦听器。要注册全局事件侦听器,您应该使用 Toolkit
class:
Toolkit.getDefaultToolkit().addAWTEventListener(listener, mask);
以下是您的案例示例:
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();
}
}
}
}
}
}
我认为即使使用 AWTEventListener 的解决方案也可行,如果有其他解决方案可用,我建议避免使用 AWTEventListener。正是因为它的强大,在各种事件到达真正的目标之前,它会在全局范围内拦截它们,所以如果中间出现任何问题(例如 NullPointerException),整个应用程序将停止工作。
我提出的解决方案利用了输入映射和操作映射,它们将对 Enter 键的处理添加到特定容器中的任何聚焦组件。
优势:
- 更安全,因为它只影响容器中的组件,而不是所有组件。
缺点:
- 相同的处理代码必须应用于需要此行为的所有容器,但这可以通过静态实用程序方法轻松完成。
示例程序如下:
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();
}
}
}
};
}