【问题标题】:How to change a focused JButton's default keybinding for ActionListener?如何更改 ActionListener 的焦点 JButton 的默认键绑定?
【发布时间】:2019-01-10 14:59:52
【问题描述】:

调用焦点 JButton 的 ActionListener 的默认键是 Space,但是如何将其更改为另一个键?

【问题讨论】:

  • 请查看编辑回答

标签: java swing key-bindings keystroke


【解决方案1】:

你需要:

  1. 更新组件的InputMap 以添加新的KeyStroke 以指向现有的Action。

  2. 防止InputMap 中的现有KeyStroke 调用现有Action。如果您希望能够使用两个 KeyStroke 来调用默认操作,则此步骤是可选的。

注意:

  1. 您需要为“按下”和“释放”键更新 InputMap
  2. 必须按上述顺序更新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());
    }
}

以上代码不需要:

  1. 创建一个虚拟Action。
  2. 操纵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();
            }
        });
*/
    }
}

【讨论】:

    【解决方案2】:

    这并不完全简单,需要:

    • 为 JButton 使用正确的 InputMap,即与 JComponent.WHEN_FOCUSED 条件关联的输入映射
    • 然后你需要获取并移除与空格键关联的按钮的InputMap和ActionMap,对于*both按键和钥匙被释放。
    • 然后将这两个操作与您感兴趣的键相关联,再次按下并释放 both 键。

    示例:

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

    【讨论】:

    • ActionMap 不需要更改:OP 只想更改击键。 @camickr 的答案是正确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 2013-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多