Java 如何使 JMenu 在 JMenuBar 中具有按钮行为

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2456501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:57:20  来源:igfitidea点击:

How to make a JMenu have Button behaviour in a JMenuBar

javaswingjmenubarjmenu

提问by Kurru

I was trying to make a JMenu behave like a JButton but I'm having some problems and hopefully someone here can help!

我试图让 JMenu 表现得像 JButton,但我遇到了一些问题,希望这里有人可以提供帮助!

I've added a MenuListener to the JMenu item with this but I cant get the popup menu/focus to leave to enable me to properly click the JMenu repeated times to trigger this function and i was hoping someone could tell me what i'm doing wrong. Thanks.

我已经用这个向 JMenu 项添加了一个 MenuListener,但我无法让弹出菜单/焦点离开以使我能够正确单击 JMenu 重复多次以触发此功能,我希望有人能告诉我我在做什么错误的。谢谢。

public void menuSelected(MenuEvent e)
        {
            ... // do stuff here code
            JMenu source = (JMenu)e.getSource();
            source.setSelected(false);
            source.setPopupMenuVisible(false);

        }

采纳答案by Nate

Not completely sure what you're asking...

不完全确定你在问什么......

But JMenuBarinherits from Container- if you'd rather add a JButtonto it than a JMenuyou can simply call -

但是JMenuBar继承自Container- 如果您更愿意JButton向其中添加 a而不是JMenu您可以简单地调用 -

JMenuBar menuBar = ....
JButton myButton = ....
menuBar.add(myButton);

回答by Kannan Ekanath

This code sample runs in eclipse, Again concerned about how you are using it?

这个代码示例在eclipse中运行,再次关心你是如何使用它的?

public class MyMenuFrame extends JFrame {


    public MyMenuFrame() throws HeadlessException {
        super("My Frame");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(400, 300);
        Container pane = this.getContentPane();
        pane.setLayout(new BorderLayout());
        pane.add(new JLabel("Hi there"), BorderLayout.PAGE_START);
        this.setVisible(true);
        JMenuBar menubar = new JMenuBar();
        JMenu menu = new JMenu("File");

        menu.addMenuListener(new MenuListener() {

            @Override
            public void menuSelected(MenuEvent e) {
                System.out.println("a");

            }

            @Override
            public void menuDeselected(MenuEvent e) {
                System.out.println("a");

            }

            @Override
            public void menuCanceled(MenuEvent e) {
                System.out.println("a");

            }
        });
        menubar.add(menu);
        this.setJMenuBar(menubar );
    }

    public static void main(String[] args) {
        new MyMenuFrame();
    }
}

回答by Daniel Bingham

It's very difficult to determine what you're trying to do here. But I don't think you are properly using JMenu.

在这里很难确定您要做什么。但我认为您没有正确使用 JMenu。

A JMenu is the object that represents a Menu. It is separate from the menu bar (JMenuBar) and from the menu item (JMenuItem). A JMenuBar usually contains multiple JMenus (File, Edit, etc) which in turn contain multiple JMenuItems (New, Open, Close). The JMenuItems are what is clicked and "acts like a button" in the menu.

JMenu 是表示 Menu 的对象。它独立于菜单栏 (JMenuBar) 和菜单项 (JMenuItem)。JMenuBar 通常包含多个 JMenu(文件、编辑等),而这些 JMenu 又包含多个 JMenuItem(新建、打开、关闭)。JMenuItems 是在菜单中被点击和“像按钮一样”的东西。

To get a menu item to act like a button, simply add it to the menu. For example:

要使菜单项像按钮一样工作,只需将其添加到菜单中即可。例如:

JMenu fileMenu = new JMenu("File");
JMenuItem newChoice = new JMenuItem("New");
newChoice.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        newHasBeenSelected();
    }
});
fileMenu.add(newChoice);

If you're trying to create a pop-up menu, you need to use JPopupMenu instead of JMenu, and you don't need a JMenuBar. Here are the Java tutorials on menus: http://java.sun.com/docs/books/tutorial/uiswing/components/menu.html

如果您正在尝试创建弹出菜单,则需要使用 JPopupMenu 而不是 JMenu,并且您不需要 JMenuBar。以下是关于菜单的 Java 教程:http: //java.sun.com/docs/books/tutorial/uiswing/components/menu.html

And here are the Java docs for JMenuBar, JMenu, JPopupMenu, and JMenuItem.

这里是JMenuBarJMenuJPopupMenuJMenuItem的 Java 文档。

If you edit your question and give a more detailed explanation of what you're doing I might be able to give more specific help.

如果您编辑您的问题并更详细地解释您在做什么,我可能会提供更具体的帮助。

回答by noResets

I know this is an old thread, but I think I might have a solution. I stumbled accross this problem in one of my apps, and found a workaround. Try using a JMenuItem instead of a JMenu. It will have the same L&F as a JMenu when you attach it to a JMenuBar. The only thing you have to do is set the size of your new "button", as your Layout Manager (even if you have not set one) will resize this component based on its own rules:

我知道这是一个旧线程,但我想我可能有一个解决方案。我在我的一个应用程序中偶然发现了这个问题,并找到了解决方法。尝试使用 JMenuItem 而不是 JMenu。当您将其附加到 JMenuBar 时,它将具有与 JMenu 相同的 L&F。您唯一要做的就是设置新“按钮”的大小,因为您的布局管理器(即使您尚未设置)将根据其自己的规则调整此组件的大小:

http://www.javaworld.com/javaworld/jw-09-2000/jw-0922-javatraps.html

http://www.javaworld.com/javaworld/jw-09-2000/jw-0922-javatraps.html

The way to do it is found under that link (if you feel uncomfortable clicking on the link, google for "setsize doesnt work" - it will be the in the top ten results). If you do not set the size properly, your new "button" will fill up the remaining space of your JMenuBar.

可以在该链接下找到执行此操作的方法(如果您觉得单击该链接不舒服,请在 google 上搜索“setsize 不起作用”-它将是前十名的结果)。如果您没有正确设置大小,您的新“按钮”将填满 JMenuBar 的剩余空间。

try this code:

试试这个代码:

menuItem.setMinimumSize(someMenu.getSize());
menuItem.setPreferredSize(someMenu.getSize());
menuItem.setMaximumSize(someMenu.getSize());
menuItem.setActionCommand("ActionText");

setActionCommand() method will set an action command, so that when you click your new "button" this will be the action command passed by the action event argument to the action performed method, so that you can easily identify it:

setActionCommand() 方法将设置一个动作命令,这样当你点击你的新“按钮”时,这将是动作事件参数传递给动作执行方法的动作命令,以便你可以轻松识别它:

public void actionPerformed(ActionEvent e) {
    System.out.println(e.getActionCommand());
}

Hope this helps!

希望这可以帮助!

回答by Bastiat

Ok I decided to investigate this a bit more and The following is the reslut and appears to act just like a JButton but appears like a jmenu on a jmenubar. Code below. (note just adding an actionListener to a JMenu didnt work right which is the reason for the mouselistener. You add an actionListener to the menubutton just like a normal button and as long as you dont add any menuitems to the menubutton (which technically you could) it will appear as a JMenu on the JMenuBar but behave like a button.

好的,我决定对此进行更多调查,以下是结果,看起来就像 JButton,但看起来像 jmenubar 上的 jmenu。代码如下。(请注意,仅向 JMenu 添加 actionListener 无法正常工作,这就是鼠标侦听器的原因。您将 actionListener 添加到 menubutton 就像普通按钮一样,只要您不向 menubutton 添加任何菜单项(从技术上讲,您可以)它将在 JMenuBar 上显示为 JMenu,但行为类似于按钮。

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.lang.reflect.Method;
import java.util.EventListener;   
import javax.swing.ImageIcon;
import javax.swing.JMenu;

public class MenuButton extends JMenu {

private boolean startedIn = false;
private ActionListener action;

public MenuButton(String title) {
    super(title);
    removeListeners(this);
    this.addMouseListener(new MenuButtonListener());

}

public MenuButton(ImageIcon icon) {
    super();
    removeListeners(this);
    this.addMouseListener(new MenuButtonListener());
    this.setIcon(icon);
}

public void addActionListener(ActionListener a) {
    action = a;
}
    //we need to remove all the listeners already associated with a JMenu. If we do
//not do this, then it will not behave as expected because some mouseclicks are eaten 
//by these listeners. There is no easy way to do that, the following method is a 
//workaroundprovided in the java bug database. 
static private void removeListeners(Component comp) {
    Method[] methods = comp.getClass().getMethods();
    for (int i = 0; i < methods.length; i++) {
        Method method = methods[i];
        String name = method.getName();
        if (name.startsWith("remove") && name.endsWith("Listener")) {

            Class[] params = method.getParameterTypes();
            if (params.length == 1) {
                EventListener[] listeners = null;
                try {
                    listeners = comp.getListeners(params[0]);
                } catch (Exception e) {
                    // It is possible that someone could create a listener
                    // that doesn't extend from EventListener. If so, ignore
                    // it
                    System.out.println("Listener " + params[0]
                            + " does not extend EventListener");
                    continue;
                }
                for (int j = 0; j < listeners.length; j++) {
                    try {
                        method.invoke(comp, new Object[] { listeners[j] });
                        // System.out.println("removed Listener " + name +
                        // " for comp " + comp + "\n");
                    } catch (Exception e) {
                        System.out
                                .println("Cannot invoke removeListener method "
                                        + e);
                        // Continue on. The reason for removing all
                        // listeners is to
                        // make sure that we don't have a listener holding
                        // on to something
                        // which will keep it from being garbage collected.
                        // We want to
                        // continue freeing listeners to make sure we can
                        // free as much
                        // memory has possible
                    }
                }
            } else {
                // The only Listener method that I know of that has more
                // than
                // one argument is removePropertyChangeListener. If it is
                // something other than that, flag it and move on.
                if (!name.equals("removePropertyChangeListener"))
                    System.out.println("    Wrong number of Args " + name);
            }
        }
    }
}

public class MenuButtonListener extends MouseAdapter {

    boolean within = false;
    boolean pressed = false;


    public void mousePressed(MouseEvent e) {
        MenuButton.this.setSelected(true);
        pressed = true;
        //System.out.println("pressed");
    }

    public void mouseReleased(MouseEvent e) {
        //System.out.println("released");
        MenuButton.this.setSelected(false);
        if (action != null && within && pressed) {
            action.actionPerformed(new ActionEvent(this,
                    ActionEvent.ACTION_PERFORMED, null));
            MenuButton.this.setSelected(false);
        }
        pressed = false;
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        within = true;
    }

    @Override
    public void mouseExited(MouseEvent e) {
        within = false;
    }
}
}