如何更改 ActionListener 的聚焦 JButton 的默认键绑定?
How to change a focused JButton's default keybinding for ActionListener?
调用聚焦 JButton 的 ActionListener 的默认键是 Space,但如何将其更改为另一个键?
这并不完全简单,需要:
- 为 JButton 使用正确的 InputMap,与
JComponent.WHEN_FOCUSED
条件关联的那个
- 然后你需要为与space键关联的按钮获取并删除InputMap和ActionMap,对于*both键按下and按键放开
- 然后将这两个操作与您感兴趣的键相关联,再次 两个 键按下并释放。
示例:
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class AlterSpaceBinding extends JPanel {
private JButton myButton = new JButton("My Button -- associate with \"B\" key");
public AlterSpaceBinding() {
myButton = alterDefaultButtonAction(myButton, KeyEvent.VK_B);
myButton.addActionListener(l -> {
System.out.println("button pressed");
});
add(myButton);
add(new JButton("Second Button -- no change"));
}
public static JButton alterDefaultButtonAction(JButton button, int desiredKeyCode) {
// get the correct InputMap
int condition = JComponent.WHEN_FOCUSED;
InputMap inputMap = button.getInputMap(condition);
ActionMap actionMap = button.getActionMap();
// empty action that does nothing
Action emptyAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
// This does NOTHING
}
};
// get both key strokes for space key, but pressed and released
KeyStroke spaceKeyPressed = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false);
KeyStroke spaceKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true);
// get input map key for pressed and released
String keyForSpacePressed = (String) inputMap.get(spaceKeyPressed);
String keyForSpaceReleased = (String) inputMap.get(spaceKeyReleased);
// get actions for press and release
Action actionForSpacePressed = actionMap.get(keyForSpacePressed);
Action actionForSpaceReleased = actionMap.get(keyForSpaceReleased);
// substitute empty action
actionMap.put(keyForSpacePressed, emptyAction);
actionMap.put(keyForSpaceReleased, emptyAction);
// key stroke for desired key code
KeyStroke desiredKeyPressed = KeyStroke.getKeyStroke(desiredKeyCode, 0, false);
KeyStroke desiredKeyReleased = KeyStroke.getKeyStroke(desiredKeyCode, 0, true);
// put in the original actions to where wanted
inputMap.put(desiredKeyPressed, desiredKeyPressed.toString());
actionMap.put(desiredKeyPressed.toString(), actionForSpacePressed);
inputMap.put(desiredKeyReleased, desiredKeyReleased.toString());
actionMap.put(desiredKeyReleased.toString(), actionForSpaceReleased);
return button;
}
private static void createAndShowGui() {
AlterSpaceBinding mainPanel = new AlterSpaceBinding();
JFrame frame = new JFrame("AlterSpaceBinding");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
您需要:
更新组件的 InputMap
以添加新的 KeyStroke
以指向现有的 Action
.
防止 InputMap
中现有的 KeyStroke
调用现有的 Action
。如果您希望能够使用两个 KeyStrokes 来调用默认操作,则此步骤是可选的。
注:
- 您需要为 "pressed" 和 "released" 键更新
InputMap
- 必须按上述顺序更新
InputMap
。
修改 Hovercrafts 示例中的代码,您可以这样做:
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class AlterSpaceBinding extends JPanel {
private JButton myButton = new JButton("My Button -- associate with \"B\" key");
public AlterSpaceBinding() {
myButton = alterDefaultButtonAction(myButton, KeyEvent.VK_B);
myButton.addActionListener(l -> {
System.out.println("button pressed");
});
add(myButton);
add(new JButton("Second Button -- no change"));
}
public static JButton alterDefaultButtonAction(JButton button, int desiredKeyCode) {
// get the correct InputMap
InputMap inputMap = button.getInputMap(JComponent.WHEN_FOCUSED);
// get both key strokes for space key, but pressed and released
KeyStroke spaceKeyPressed = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false);
KeyStroke spaceKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true);
// key stroke for desired key code
KeyStroke desiredKeyPressed = KeyStroke.getKeyStroke(desiredKeyCode, 0, false);
KeyStroke desiredKeyReleased = KeyStroke.getKeyStroke(desiredKeyCode, 0, true);
// share the Action with desired KeyStroke
inputMap.put(desiredKeyPressed, inputMap.get(spaceKeyPressed));
inputMap.put(desiredKeyReleased, inputMap.get(spaceKeyReleased));
// disable original KeyStrokes (optional)
inputMap.put(spaceKeyPressed, "none");
inputMap.put(spaceKeyReleased, "none");
return button;
}
private static void createAndShowGui() {
AlterSpaceBinding mainPanel = new AlterSpaceBinding();
JFrame frame = new JFrame("AlterSpaceBinding");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
以上代码不需要:
- 创建一个虚拟对象
Action
。
- 操纵
ActionMap
.
查看 Using Key Bindings 以获取更多操作组件 InputMap
和 ActionMap
的示例。
注:
更有可能的情况是您想要更新应用程序中所有按钮的绑定,以便拥有一个通用的 LAF。在这种情况下,您可以从所有 JButton 共享的 UIManager 更新 "focusInputMap":
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SSCCE extends JPanel
{
SSCCE()
{
add( new JButton("Button 1" ) );
add( new JButton("Button 2" ) );
add( new JButton("Button 3" ) );
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
// Update shared InputMap
InputMap inputMap = (InputMap)UIManager.get("Button.focusInputMap");
int desiredKeyCode = KeyEvent.VK_B; // type "b" to invoke Action on button
KeyStroke spaceKeyPressed = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false);
KeyStroke spaceKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true);
// key stroke for desired key code
KeyStroke desiredKeyPressed = KeyStroke.getKeyStroke(desiredKeyCode, 0, false);
KeyStroke desiredKeyReleased = KeyStroke.getKeyStroke(desiredKeyCode, 0, true);
// share the Action with desired KeyStroke
inputMap.put(desiredKeyPressed, inputMap.get(spaceKeyPressed));
inputMap.put(desiredKeyReleased, inputMap.get(spaceKeyReleased));
// optionally disable original KeyStrokes
inputMap.put(spaceKeyPressed, "none");
inputMap.put(spaceKeyReleased, "none");
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
调用聚焦 JButton 的 ActionListener 的默认键是 Space,但如何将其更改为另一个键?
这并不完全简单,需要:
- 为 JButton 使用正确的 InputMap,与
JComponent.WHEN_FOCUSED
条件关联的那个 - 然后你需要为与space键关联的按钮获取并删除InputMap和ActionMap,对于*both键按下and按键放开
- 然后将这两个操作与您感兴趣的键相关联,再次 两个 键按下并释放。
示例:
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class AlterSpaceBinding extends JPanel {
private JButton myButton = new JButton("My Button -- associate with \"B\" key");
public AlterSpaceBinding() {
myButton = alterDefaultButtonAction(myButton, KeyEvent.VK_B);
myButton.addActionListener(l -> {
System.out.println("button pressed");
});
add(myButton);
add(new JButton("Second Button -- no change"));
}
public static JButton alterDefaultButtonAction(JButton button, int desiredKeyCode) {
// get the correct InputMap
int condition = JComponent.WHEN_FOCUSED;
InputMap inputMap = button.getInputMap(condition);
ActionMap actionMap = button.getActionMap();
// empty action that does nothing
Action emptyAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
// This does NOTHING
}
};
// get both key strokes for space key, but pressed and released
KeyStroke spaceKeyPressed = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false);
KeyStroke spaceKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true);
// get input map key for pressed and released
String keyForSpacePressed = (String) inputMap.get(spaceKeyPressed);
String keyForSpaceReleased = (String) inputMap.get(spaceKeyReleased);
// get actions for press and release
Action actionForSpacePressed = actionMap.get(keyForSpacePressed);
Action actionForSpaceReleased = actionMap.get(keyForSpaceReleased);
// substitute empty action
actionMap.put(keyForSpacePressed, emptyAction);
actionMap.put(keyForSpaceReleased, emptyAction);
// key stroke for desired key code
KeyStroke desiredKeyPressed = KeyStroke.getKeyStroke(desiredKeyCode, 0, false);
KeyStroke desiredKeyReleased = KeyStroke.getKeyStroke(desiredKeyCode, 0, true);
// put in the original actions to where wanted
inputMap.put(desiredKeyPressed, desiredKeyPressed.toString());
actionMap.put(desiredKeyPressed.toString(), actionForSpacePressed);
inputMap.put(desiredKeyReleased, desiredKeyReleased.toString());
actionMap.put(desiredKeyReleased.toString(), actionForSpaceReleased);
return button;
}
private static void createAndShowGui() {
AlterSpaceBinding mainPanel = new AlterSpaceBinding();
JFrame frame = new JFrame("AlterSpaceBinding");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
您需要:
更新组件的
InputMap
以添加新的KeyStroke
以指向现有的Action
.防止
InputMap
中现有的KeyStroke
调用现有的Action
。如果您希望能够使用两个 KeyStrokes 来调用默认操作,则此步骤是可选的。
注:
- 您需要为 "pressed" 和 "released" 键更新
InputMap
- 必须按上述顺序更新
InputMap
。
修改 Hovercrafts 示例中的代码,您可以这样做:
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class AlterSpaceBinding extends JPanel {
private JButton myButton = new JButton("My Button -- associate with \"B\" key");
public AlterSpaceBinding() {
myButton = alterDefaultButtonAction(myButton, KeyEvent.VK_B);
myButton.addActionListener(l -> {
System.out.println("button pressed");
});
add(myButton);
add(new JButton("Second Button -- no change"));
}
public static JButton alterDefaultButtonAction(JButton button, int desiredKeyCode) {
// get the correct InputMap
InputMap inputMap = button.getInputMap(JComponent.WHEN_FOCUSED);
// get both key strokes for space key, but pressed and released
KeyStroke spaceKeyPressed = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false);
KeyStroke spaceKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true);
// key stroke for desired key code
KeyStroke desiredKeyPressed = KeyStroke.getKeyStroke(desiredKeyCode, 0, false);
KeyStroke desiredKeyReleased = KeyStroke.getKeyStroke(desiredKeyCode, 0, true);
// share the Action with desired KeyStroke
inputMap.put(desiredKeyPressed, inputMap.get(spaceKeyPressed));
inputMap.put(desiredKeyReleased, inputMap.get(spaceKeyReleased));
// disable original KeyStrokes (optional)
inputMap.put(spaceKeyPressed, "none");
inputMap.put(spaceKeyReleased, "none");
return button;
}
private static void createAndShowGui() {
AlterSpaceBinding mainPanel = new AlterSpaceBinding();
JFrame frame = new JFrame("AlterSpaceBinding");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
以上代码不需要:
- 创建一个虚拟对象
Action
。 - 操纵
ActionMap
.
查看 Using Key Bindings 以获取更多操作组件 InputMap
和 ActionMap
的示例。
注:
更有可能的情况是您想要更新应用程序中所有按钮的绑定,以便拥有一个通用的 LAF。在这种情况下,您可以从所有 JButton 共享的 UIManager 更新 "focusInputMap":
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SSCCE extends JPanel
{
SSCCE()
{
add( new JButton("Button 1" ) );
add( new JButton("Button 2" ) );
add( new JButton("Button 3" ) );
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
// Update shared InputMap
InputMap inputMap = (InputMap)UIManager.get("Button.focusInputMap");
int desiredKeyCode = KeyEvent.VK_B; // type "b" to invoke Action on button
KeyStroke spaceKeyPressed = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false);
KeyStroke spaceKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true);
// key stroke for desired key code
KeyStroke desiredKeyPressed = KeyStroke.getKeyStroke(desiredKeyCode, 0, false);
KeyStroke desiredKeyReleased = KeyStroke.getKeyStroke(desiredKeyCode, 0, true);
// share the Action with desired KeyStroke
inputMap.put(desiredKeyPressed, inputMap.get(spaceKeyPressed));
inputMap.put(desiredKeyReleased, inputMap.get(spaceKeyReleased));
// optionally disable original KeyStrokes
inputMap.put(spaceKeyPressed, "none");
inputMap.put(spaceKeyReleased, "none");
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}