JMenuItem accelerator not working when menu bar is

2019-07-16 05:49发布

This question is a follow-up to this question.

I have a JMenuBar whose behavior is like the menu bars in Firefox and iTunes. That is, the menu bar is initially hidden, but when you press Alt, the menu bar appears.

The answer to the other question solved the problem of achieving that functionality, but it brought about another issue: The JMenuItem accelerators are not working when the JMenuBar is not visible. In other words, you must press Alt before CTRL+F (the installed accelerator) will work.

This is not supposed to be the case, though, because the setAccelerator() method states the following:

public void setAccelerator(KeyStroke keyStroke)

Sets the key combination which invokes the menu item's action listeners without navigating the menu hierarchy. It is the UI's responsibility to install the correct action. Note that when the keyboard accelerator is typed, it will work whether or not the menu is currently displayed.

So, I'm wondering if this is another Java bug?

SSCCE (to get the menu to appear, you press Alt, and the installed accelerator is CTRL+F for "Find" which brings up a dummy JOptionPane for input):

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class MenuBarTest extends JFrame {

    public MenuBarTest() {
        JMenu jMenu1 = new JMenu();
        JMenu jMenu2 = new JMenu();
        final JMenuBar jMenuBar1 = new JMenuBar();
        JMenuItem jMenuItem1 = new JMenuItem();
        JMenuItem jMenuItem2 = new JMenuItem();

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        jMenu1.setText("File");
        jMenuItem1.setText("jMenuItem1");
        jMenu1.add(jMenuItem1);
        jMenuBar1.add(jMenu1);
        jMenu2.setText("Edit");
        jMenuItem2.setText("Find");
        jMenu2.add(jMenuItem2);
        jMenuBar1.add(jMenu2);
        setJMenuBar(jMenuBar1);

        jMenuBar1.setVisible(false);
        ChangeListener listener = new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                MenuElement[] elements = MenuSelectionManager.defaultManager().getSelectedPath();
                jMenuBar1.setVisible(elements.length > 0 && elements[0] == jMenuBar1);
            }
        };
        MenuSelectionManager.defaultManager().addChangeListener(listener);

        jMenuItem2.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem2.setText("Find");
        jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                String what = JOptionPane.showInputDialog(MenuBarTest.this, "Search for what?");
                System.out.println(what);
            }
        });

        pack();
        setSize(500,500);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    public static void main(String args[]) {
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
            ex.printStackTrace();
        }
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new MenuBarTest();
            }
        });
    }
}

1条回答
闹够了就滚
2楼-- · 2019-07-16 06:09

Read your emphasis carefully

Note that when the keyboard accelerator is typed, it will work whether or not the menu is currently displayed.

This talks about the menu not its parent. Meaning that the menu might be currently not displayed. Nevertheless, the real (probably not overly well documented) desisive property is that it must be showing. Had updated my answer to your previous question.

查看更多
登录 后发表回答