使用空格键触发JButton,或输入键或鼠标单击

我正在尝试使用单个按钮获取一个简单的JFrame,以便在发生任何这些事件时触发事件:

  • 按下Enter键并且JButton具有焦点
  • 按下空格键并且JButton具有焦点
  • 单击JButton。

在JButton上使用addActionListener看来,Enter和空格键似乎是“免费”和默认鼠标点击。 麻烦的是,我已经读过,键绑定取决于所使用的外观。

我试图通过将Enter和空格键添加到JButton的动作映射来获得跨LaF的通用行为,甚至添加了一个随机键(“m”)以确保ActionMap正在完成工作(它是),但现在是鼠标点击丢失。 我似乎能够获得所有键和鼠标单击的唯一方法是使用动作映射和addActionListener。

有没有办法让这些键和鼠标绑定在所有LaF中一致地工作,而不试图检测可能出现的每个可能的LaF? 我可以注册一个动作侦听器,它将触发键和鼠标事件吗?

我最喜欢的解决方案是在JButton动作图中添加鼠标点击,并检测动作内部发生的键或鼠标点击。

我还在这里学习绳索,所以这可能不是最好或最有效的做事方式; 我确信它过度设计了。 这是一种训练练习,我正在试验我能掌握的一切。 欢迎任何和所有编码风格的评论!

import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.UIManager; public class Example extends JFrame { // ============================ private class BtnListener extends AbstractAction { private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent ae) { System.out.println("\nclick button listener triggered"); System.out.println(ae.getSource().getClass().toString()); } } // class BtnListener private static final int NO_MODIFIER = 0; private static final boolean ON_KEY_PRESS = false; private static final KeyStroke ENTER_PRESSED = KeyStroke.getKeyStroke( KeyEvent.VK_ENTER, NO_MODIFIER, ON_KEY_PRESS); private static final KeyStroke M_PRESSED = KeyStroke.getKeyStroke( KeyEvent.VK_M, NO_MODIFIER, ON_KEY_PRESS); private static final KeyStroke SPACEBAR_PRESSED = KeyStroke.getKeyStroke( KeyEvent.VK_SPACE, NO_MODIFIER, ON_KEY_PRESS); private JButton btnButton; private final AbstractAction btnListener = new BtnListener(); private JPanel buttonPanel; private JFrame frmMain; public static void main(String[] args) { Example ex = new Example(); ex.displayFrame(); } Action btnActionListener = new AbstractAction() { private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { System.out.println("\nkey button action triggerred"); System.out.println(e.getSource().getClass().toString()); if (e.getSource() instanceof JButton) { System.out.println("button"); } else { System.out.println("Something else"); } } }; public Example() { initialize(); } public void displayFrame() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (Throwable e) { e.printStackTrace(); } EventQueue.invokeLater(new Runnable() { public void run() { try { frmMain.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } private void initialize() { frmMain = new JFrame(); btnButton = new JButton("Abutton"); // Comment this out, you lose the mouse click btnButton.addActionListener(btnListener); // Comment out ActionMaps, but keep addActionListner (above), and // only lose M_PRESSED InputMap buttonFocusedMap = btnButton .getInputMap(JComponent.WHEN_FOCUSED); buttonFocusedMap.put(ENTER_PRESSED, "blah"); btnButton.getActionMap().put("blah", btnActionListener); buttonFocusedMap.put(SPACEBAR_PRESSED, "blort"); btnButton.getActionMap().put("blort", btnActionListener); buttonFocusedMap.put(M_PRESSED, "gaaak"); btnButton.getActionMap().put("gaaak", btnActionListener); // Is there a way to add a mouse click to the ActionMap? buttonPanel = new JPanel(); buttonPanel.add(btnButton); frmMain.getContentPane().add(buttonPanel); frmMain.setBounds(100, 100, 500, 432); frmMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } 

BasicButtonListener使用的BasicButtonUI确保在聚焦时所有按钮(检查,无线电,切换)都绑定到Space 。 这适用于跨平台,即使单独的外观和感觉可以唯一地呈现各种按钮模型状态。 压制空间唤起了压制的 UIAction ,释放空间唤起了释放的 UIAction 。 在按钮界限内按下并释放鼠标时也会出现同样的情况; 在按下时拖动按钮外部以查看待命状态的变化。

在任何一种情况下, 按下释放的组合都会调用按钮的actionPerformed()方法。

无论焦点如何,将Enter绑定到Action一种便捷方法是通过根窗格的setDefaultButton()方法。 此示例说明了单击按钮的所有三种方法。

您可以(也可能应该)做的是创建一个AbstractAction。 您可以将AbstractAction用于ActionMap以及单击(执行JButton.setAction(…))