简体   繁体   English

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

[英]How to prevent a disabled JMenuItem from hiding the menu when being clicked?

In my Java swing application i have noticed that when i click on a disabled JMenuItem in a JPopupMenu it hides the menu, but ii do not want to hide it, as if nothing is clicked. 在我的Java swing应用程序中,我注意到当我在JPopupMenu中单击禁用的JMenuItem时,它隐藏了菜单,但是我不想隐藏它,好像没有点击任何内容。 Is there a way to prevent this ? 有办法防止这种情况吗?

-----------------------------------> Update: Added Code sample : -----------------------------------> 更新:添加代码示例:

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." );
}

我认为在Java7中这已得到修复。

not sure how to prevent. 不知道如何预防。 but you can setVisible(false) to prevent it being displayed. 但你可以setVisible(false)来防止它被显示。 Also if a user clicks on the disable menu no action will take place. 此外,如果用户单击禁用菜单,则不会执行任何操作。

When you are disabling JMenuItem, you should remove the ActionListener associated with that JMenuItem by using jMenuItem.removeActionListener() method. 禁用JMenuItem时,应使用jMenuItem.removeActionListener()方法删除与该JMenuItem关联的ActionListener。 If u remove that that action will not call the listener and popup will not be disappeared. 如果你删除那个动作将不会调用监听器,弹出窗口将不会消失。 I hope this will help to achieve your target. 我希望这有助于实现您的目标。

In short, you can do this, but you will have to write your own mouse listener, which may require a lot of copy&paste from the jdk source code, which is not a very good idea, and I'm not sure about what license restrictions it will put on your code. 简而言之,你可以这样做,但你必须编写自己的鼠标监听器,这可能需要从jdk源代码中进行大量的复制和粘贴,这不是一个好主意,而且我不确定哪些许可限制它会把你的代码。

I would start digging from this method: 我会从这个方法开始挖掘:

javax.swing.plaf.basic.BasicMenuItemUI.Handler#mouseReleased

which seems to be the entry point from where the menu handling mechanism hides the popup. 这似乎是菜单处理机制隐藏弹出窗口的入口点。 I would take a closer look at 我会仔细看看

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

EDIT Developing answer by @Burhan Valikarimwala, try this apporach: remove all action listeners from the disabled JMenuItem and store them in some static temp structure (let's say a Map<WeakReference<JMenuItem>, List<MouseListener>> ), this way it will not hide the popup. 编辑 @Burhan Valikarimwala开发答案,试试这个apporach:从禁用的JMenuItem中删除所有动作监听器并将它们存储在一些静态临时结构中(假设一个Map<WeakReference<JMenuItem>, List<MouseListener>> ),这样它会不要隐藏弹出窗口。 When you make the menu item enabled again, add all the listeners back. 再次启用菜单项时,请添加所有侦听器。 Make it into some util method and it will be seamless. 将它变成一些util方法,它将是无缝的。

did you gave a try at this method: http://download.oracle.com/javase/6/docs/api/javax/swing/JMenuItem.html#setArmed%28boolean%29 你试过这个方法了吗: http//download.oracle.com/javase/6/docs/api/javax/swing/JMenuItem.html#setArmed%28boolean%29

"arm the menu item so it can be selected", which I guess would do the trick if set to false. “设置菜单项以便可以选择它”,如果设置为false,我想这会成功。

The only solution I could come up with, for your problem of a click on disable JMenuItem causing it to hide is below: 我能提出的唯一解决方案,因为你点击禁用JMenuItem使其隐藏的问题如下:


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());
            }
        }
    }
}

Basically the hiding happens when your release is inside the bounds of the JMenuItem, therefore we are checking if it is disabled then we show popup again. 基本上隐藏发生在你的发布在JMenuItem的边界内时,因此我们检查它是否被禁用然后我们再次显示弹出窗口。 As by this time it is already decided that it will be hidden. 到目前为止,已经确定它将被隐藏。 I was trying calling super.mouseRelease with a different MouseEvent pointing outside component and consuming the previous one but it helps nothing. 我正在尝试使用指向组件外部的不同MouseEvent调用super.mouseRelease并使用前一个,但它没有任何帮助。

Anyway this solution works. 无论如何这个解决方案有效 Enjoy, Boro 享受,博罗

This has been tested and works. 这已经过测试和运作。

The Look & Feel decides how to handle the mouse events on disabled menu items. 外观和感觉决定如何处理禁用菜单项上的鼠标事件。 Anyway, you can intercept the undesired events by using a custom MenuItem . 无论如何,您可以使用自定义MenuItem 拦截不需要的事件。 Simply use that code (copy/paste): 只需使用该代码(复制/粘贴):

public class CustomMenuItem extends JMenuItem {

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

    public CustomMenuItem() {
        super();
    }

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

First, adapt the code to suit your needs (optional). 首先,根据您的需求调整代码(可选)。
Finally, replace any JMenuItem with a CustomMenuItem . 最后, CustomMenuItem 替换任何JMenuItem

That's it! 而已!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM