Focus on first jmenubar item on “alt” key press

2019-05-20 21:19发布

Is there any way to auto-select a jmenu within my jmenubar when the user's pressing the "ALT" key ? (Like windows softwares)

The problem is that the default behavior of my jframe, when the "ALT" key is pressed, is to show up a menu containing the following actions : restore, move, size, reduce, ...

What I want my java application to do, is to select my jmenu first item when "alt" is pressed. (Like it would do with a mnemonic : "alt + f")

4条回答
家丑人穷心不美
2楼-- · 2019-05-20 21:50

Add the action to the ActionMap and InputMap of your JRootPane. See below:

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


public class MenuExample {

    private void setupMenuKey(final JFrame frame) {
        Action menuAction = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JRootPane rootPane = frame.getRootPane();
                JMenuBar jMenuBar = rootPane.getJMenuBar();
                JMenu menu = jMenuBar.getMenu(0);
                menu.doClick();
            }
        };

        JRootPane rootPane = frame.getRootPane();
        ActionMap actionMap = rootPane.getActionMap();

        final String MENU_ACTION_KEY = "expand_that_first_menu_please";
        actionMap.put(MENU_ACTION_KEY, menuAction);
        InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ALT, 0, true), MENU_ACTION_KEY);
    }


    private JFrame build() {
        JFrame frame = new JFrame("Hello");
        frame.setSize(300, 300);

        JMenuBar bar = new JMenuBar();

        List<String> letters = Arrays.asList("A", "B", "C");
        for (int i = 0; i < 3; i++) {
            JMenu menu = new JMenu("Menu " + i);
            for (String string : letters) {
                menu.add(new JMenuItem(String.format("Menu %s - %s", i, string)));
            }
            bar.add(menu);
        }
        frame.setJMenuBar(bar);

        JButton b = new JButton("click");
        JPanel p = new JPanel();
        p.add(b);
        frame.add(p);
        setupMenuKey(frame);

        return frame;
    }

    public static void main(String[] args) {
        MenuExample menuExample = new MenuExample();
        JFrame frame = menuExample.build();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }


}
查看更多
Emotional °昔
3楼-- · 2019-05-20 21:54

I've found the response very useful, but also with a drawback.

Imagine you're using Cross PlatForm L&F (Metal) and you've defined mnemonics to all the menus; you know that those menus are invoked against pressing . So, if we put the solution provided by black panda the results on a pressing are first we watch the desired menu deployed but immediately after switches to the first menu.

I think that the best way would be on ALT pressing only the first menu should be selected but without showing its contents (Those contents shoud appear on a down key pressing). Is there any way to do this in Cross Platform L&F?.

Alternatively there is another way to proceed without any extra code. If we invoke the System L&F (Windows in my case) the ALT key behaves as desired. See stackoverflow question 13474555 for details.

查看更多
The star\"
4楼-- · 2019-05-20 21:58

Use actionmap and inputmap of JComponent to do this job. Since JFrame is not a descendant of JCompoenent i would suggest you adding JPanel to your jframe and then,

Action action = new AbstractAction() {

        @Override
        public void actionPerformed(ActionEvent e) {
            jMenu1.doClick();
        }
    };
    jPanel1.getActionMap().put("myAction", action);
    jPanel1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ALT, KeyEvent.ALT_DOWN_MASK), "myAction");
查看更多
你好瞎i
5楼-- · 2019-05-20 22:09

I have found just by using frame.setJMenuBar(jmenubar); where frame is your JFrame and jmenubar is your JMenuBar, it'll automatically do this. You don't even have to add it to your layout manager.

查看更多
登录 后发表回答