Java 如何防止禁用的JMenuItem在单击时隐藏菜单?

Java 如何防止禁用的JMenuItem在单击时隐藏菜单?,java,swing,jpopupmenu,jmenuitem,Java,Swing,Jpopupmenu,Jmenuitem,在我的JavaSwing应用程序中,我注意到,当我单击JPopupMenu中禁用的JMenuItem时,它会隐藏菜单,但我不想隐藏它,就好像什么都没有单击一样。有没有办法防止这种情况 ----------------------------------->更新:添加代码示例: JMenuItem saveMenuItem = new JMenuItem(); saveMenuItem.setEnabled(false); saveMenuItem.addActionListener(new

在我的JavaSwing应用程序中,我注意到,当我单击JPopupMenu中禁用的JMenuItem时,它会隐藏菜单,但我不想隐藏它,就好像什么都没有单击一样。有没有办法防止这种情况

----------------------------------->更新:添加代码示例:

JMenuItem saveMenuItem = new JMenuItem();

saveMenuItem.setEnabled(false);

saveMenuItem.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        saveMenuItemActionPerformed();
    }
});
add(saveMenuItem);

private void saveMenuItemActionPerformed() {
    System.out.println( "Save clicked." );
}

不知道如何预防。但您可以设置Visible(false)以防止其显示。此外,如果用户单击禁用菜单,则不会执行任何操作

禁用JMenuItem时,应使用删除与该JMenuItem关联的ActionListener 方法。 如果您删除该操作,该操作将不会调用侦听器,弹出窗口也不会消失。
我希望这将有助于实现您的目标。

简而言之,您可以做到这一点,但您必须编写自己的鼠标侦听器,这可能需要大量复制和粘贴jdk源代码,这不是一个很好的主意,而且我不确定它会对您的代码施加哪些许可限制

我会从这个方法开始挖掘:

javax.swing.plaf.basic.BasicMenuItemUI.Handler#mouseReleased
这似乎是菜单处理机制隐藏弹出窗口的入口点。我会仔细看看

javax.swing.plaf.basic.BasicPopupMenuUI.MouseGrabber#stateChanged

编辑@Burhan Valikarimwala开发的答案,尝试以下方法:从禁用的JMenuItem中删除所有动作侦听器,并将它们存储在某个静态临时结构中(比如一个
Map
),这样它就不会隐藏弹出窗口。再次启用菜单项时,请将所有侦听器添加回。将它转换成某种util方法,它将是无缝的。

您是否尝试过这种方法:


“设置菜单项以便选中它”,如果设置为false,我想这会起作用。

我能想到的唯一解决方案是,单击“禁用”菜单项导致它隐藏的问题如下:


import java.awt.Color;
import java.awt.Dimension;
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 javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;

public class PopupMenuDisableNoCloseTest extends JPanel implements ActionListener
{
    public static void main(String[] args)
    {
        PopupMenuDisableNoCloseTest p = new PopupMenuDisableNoCloseTest();
        p.setPreferredSize(new Dimension(200, 300));
        p.setBackground(Color.GREEN);
        JPanel contentPane = new JPanel();
        contentPane.add(p);
        final JFrame f = new JFrame();
        final JPopupMenu popup = new JPopupMenu();
        final JMenuItem menuItem1 = new JMenuItem("A popup menu item");
        menuItem1.addActionListener(p);
        menuItem1.addMouseListener(new MouseAdapter()
        {
            @Override
            public void mousePressed(MouseEvent e)
            {
                System.out.println(" menuItem1 mousePressed e.getPoint()=" + e.getPoint());
            }

            @Override
            public void mouseReleased(MouseEvent e)
            {
                System.out.println(" menuItem1 mouseReleased e.getPoint()=" + e.getPoint());
                if(!menuItem1.isEnabled())
                    popup.setVisible(true);
            }
        });
        menuItem1.setEnabled(false);
        popup.add(menuItem1);
        JMenuItem menuItem2 = new JMenuItem("Another popup menu item");
        menuItem2.addActionListener(p);
        popup.add(menuItem2);
        MouseListener popupListener = new PopupListener(popup);
        f.addMouseListener(popupListener);
        f.setContentPane(contentPane);
        f.setSize(800, 600);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        JMenuItem source = (JMenuItem) (e.getSource());
        String s = "Action event detected. Event source: " + source.getText();
        System.out.println("s=" + s);
    }

    static class PopupListener extends MouseAdapter
    {
        JPopupMenu popup;
        PopupListener(JPopupMenu popupMenu)
        {
            popup = popupMenu;
        }

        @Override
        public void mousePressed(MouseEvent e)
        {
            maybeShowPopup(e);
        }

        @Override
        public void mouseReleased(MouseEvent e)
        {
            maybeShowPopup(e);
        }

        private void maybeShowPopup(MouseEvent e)
        {
            if(e.isPopupTrigger())
            {
                popup.show(e.getComponent(),
                        e.getX(), e.getY());
            }
        }
    }
}

基本上,隐藏发生在您的发布在JMenuItem的边界内时,因此我们正在检查它是否被禁用,然后再次显示弹出窗口。因为此时已经决定将其隐藏。我试着调用super.mouseerelease,使用另一个MouseEvent指向组件外部并使用前一个组件,但它没有任何帮助

无论如何,这个解决方案是有效的。 尽情享受吧,波罗

这已经过测试,效果良好

外观决定如何处理禁用菜单项上的鼠标事件。无论如何,您可以使用自定义的
菜单项
截获不需要的事件。只需使用该代码(复制/粘贴):

首先,调整代码以满足您的需要(可选)。
最后,
CustomMenuItem
替换任何
JMenuItem


就这样

我认为在Java7中,这一点已经被修复。

您能展示一下您编写的代码吗?@harshit:我附上了一个代码示例,介绍了如何初始化JMenuItem。我在单击事件中不执行任何操作。。。这个菜单隐藏只是默认的Java行为。为了更快地获得更好的帮助,请发布SSCCE()而不是代码片段。@安德鲁:谢谢安德鲁。下次我会这么做。对不起,我不明白你说的setVisible(false)是什么意思?你可以执行saveMenuItem.setVisible(false),但我想让它可见并禁用!如果我单击了禁用的项目,则不会执行任何操作,但菜单将关闭。试试看。@jmendeth。。。对于JComboBox禁用的项目是否有类似的解决方案?@Brad是的,只需创建自己的JComboBox类并将
processMouseeEvent
方法复制到其中即可。然后用类替换任何JComboBox。如果你愿意,我可以发布一个例子。@jmendeth。。。我不明白。。。processMouseEvent不应该应用于JComboBox项,而不是JComboBox本身吗。。。如果你能给我举个例子,我将不胜感激。@Brad对不起,我没有正确表达。是的,
processMouseEvent
必须应用于弹出窗口中的所有项目。在本例中,组合框中的项目是@jmendeth。。。嗯,谢谢你。
public class CustomMenuItem extends JMenuItem {

    public CustomMenuItem(String text) {
        super(text);
    }

    public CustomMenuItem() {
        super();
    }

    protected void processMouseEvent(MouseEvent e) {
        if (isEnabled()) super.processMouseEvent(e);
    }
}