I'm trying to get a simple JFrame with a single button to fire an event when any of these events happen:
It seems that the Enter and Spacebar come "for free" along with the default mouse click using addActionListener on the JButton; trouble is, I've read that the the key bindings are dependent on the Look and Feel used.
I've tried to get universal behavior across LaF by adding Enter and Spacebar to the JButton's action map, and even added a random key ("m") to make sure the ActionMap was doing the work (it was), but now the mouse click is lost. The only way I seem to be able to get all the keys and mouse click is to use both action map and addActionListener.
Is there a way to get these key and mouse bindings to work consistently across all LaF without trying to detect every possible LaF that may come along? Can I register a single action listener that will fire on both key and mouse events?
My favorite solution would be to add a mouse click to the JButton action map and detect which key or mouse click happened inside the inside the action.
I'm still learning the ropes here, so this probably isn't the best or most efficient way to do things; I'm sure it's over-engineered. This is sort of training exercise where I'm experimenting with everything I can get my hands on. Any and all coding style comments are welcome!
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
, used by BasicButtonUI
, ensures that all buttons (check, radio, toggle) are bound to Space when focused. This works across platforms, even though individual Look & Feels may render various button model states uniquely. Pressing Space evokes the pressed UIAction
, and releasing Space evokes the released UIAction
. The same occurs when the mouse is pressed and released within the button's bounds; drag outside the button while pressed to see the armed state change.
In either case, the combination of pressed and released invokes your button's actionPerformed()
method.
One convenient way to bind Enter to an Action
, irrespective of focus, is via the root pane's setDefaultButton()
method. This example illustrates all three ways to click a button.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With