Search code examples
javaactionlistenerhotkeysjmenubar

invisible JMenuBar, Accelerator not working


My Program has a JMenuBar with JMenuItems. They have a ActionListener, and I set a Shortcut with setAccelerator. Now I am hiding the menu bar when the window become unfocused, to get more space for a displayed image. But after the first hiding of the menubar, the hotkeys just stop working.

How can I fix that?

I created a little example code to illustrate that strange behavior:

import javax.swing.*;
import java.awt.event.*;

class Example extends JFrame{
    public static void main(String[] args) {
        new Example(); //main is static
    }
    static JMenuBar menubar; //be accessable for the ActionListener
    Example() {
        //JPanel
        this.setSize(50,50);
        this.setVisible(true);  

        //Menubar, static
        menubar = new JMenuBar();
        this.setJMenuBar(menubar);

        //Menu
        JMenu filemenu = new JMenu("File");
        menubar.add(filemenu);

        //Item
        JMenuItem menuitem = new JMenuItem("Do Something...");
        filemenu.add(menuitem);
        menuitem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.SHIFT_DOWN_MASK)); // Shift + D
        menuitem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Action!");
            }
        });

        JButton button = new JButton("Show/Hide menubar");
        this.add(button);
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Toggle Bar!");
                menubar.setVisible(!menubar.isVisible()); //Toggle
            }
        });
    }
}

For reference: I'm using Java 1.7.0_60-ea (Java 7) on a Mac. But this error occurs independent of using the Mac native menu bar or the normal java menu bar inside the JFrame.


Solution

  • You could try to add global keybindings. How to add keybindings is explained here.

    Here is an example of what you could do:

    //Any component that is always visible in the window (like the image)
    JComponent c;
    //Get input and action map
    InputMap imap = c.getInputMap(WHEN_IN_FOCUSED_WINDOW);
    ActionMap amap = c.getActionMap();
    //Put keybinding and action
    imap.put(KeyStroke.getKeyStroke("shift D"), "doSomething");
    amap.put("doSomething", anAction);
    

    Note that it only works in the focused window. But should work regardless of the menubar being visible or not.