Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swing: Setting a function key (F2) as an accelerator

I have a menu item, "rename", for which F2 is set as an accelerator. Indeed when the menu is displayed there a little "F2" indication next to "rename".

Sadly, this does not work. This accelerator triggers no response. When I change the accelerator to CTRL+F2 - it works.

It seems that I should use an InpoutMpa/ActionMap. The problem with that is that I want this to work everywhere in the app so I am trying to associate it with the top-level JFrame. But, JFrame does not have a getInputMap() method.

Lost.

[Added]

     ks = KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0);
     JMenuItem mi = new JMenuItem("Rename");
     mi.setAccelerator(ks);
     mi.addActionListener(action); 
like image 278
Itay Maman Avatar asked Jan 07 '10 09:01

Itay Maman


2 Answers

This is probably happening because JTable uses F2 to invoke the StartEditing action (I saw the same behavior on one of my programs and traced it to this).

There are a couple of solutions. The most drastic is to remove this input mapping (I believe this code actually removes the mapping from all JTables):

KeyStroke keyToRemove = KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0);

InputMap imap = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
while (imap != null)
{
    imap.remove(keyToRemove);
    imap = imap.getParent();
}

Or, if you're using the table for display only, and don't plan to let the user edit it, you could make it non-focusable:

table.setFocusable(false);

On a completely different subject, I strongly recommend creating an AbstractAction subclass for your menu items, rather than creating them "from scratch". Aside from giving you very simple menu setup code, you can use the same action instance for both the main menu and a popup/toolbar, and enable/disable them both at the same time.

like image 73
kdgregory Avatar answered Oct 18 '22 01:10

kdgregory


I know this is an old thread, but I struggled with the exact same thing as the original poster and found the solution. The JFrame itself doesn't have a getInputMap method, but its root pane does. So you have to use "getRootPane.getInputMap" instead.

Example code:

public class ApplicationFrame extends JFrame {
    private AbstractAction f2Action = new AbstractAction() {
        private static final long serialVersionUID = 1L;

        public void actionPerformed(ActionEvent e) {
            // Do something useful
        }
    };

    public ApplicationFrame() {

        InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = getRootPane().getActionMap(); 

        inputMap.put(KeyStroke.getKeyStroke("F2"), "f2Action");
        actionMap.put("f2Action", f2Action);

    }
}
like image 26
Mikkel Avatar answered Oct 18 '22 01:10

Mikkel