0

我正在开发一个 Swing 应用程序,我想在其中输入键作为JFrameJButton组件和对话框之外的所有组件的选项卡键。为此,我将 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 键作为 Action onJButton和 Dialog Boxes工作。

4

2 回答 2

1

这是可能的,但使用另一种方式:全局事件监听器。要注册一个全局事件监听器,你应该使用这个Toolkit类:

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();
                    }
                }
            }
        }

    }
}
于 2018-05-21T06:31:41.073 回答
0

我认为即使使用 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();
                }
            }
        }
    };
}
于 2018-05-21T17:06:19.573 回答