开发者

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 i i do not want to hide it, as if nothing is clicked. 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." );
}


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. 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.

That's it!


not sure how to prevent. but you can setVisible(false) to prevent it being displayed. 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. 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.


did you gave a try at this method: 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.


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.

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. When you make the menu item enabled again, add all the listeners back. Make it into some util method and it will be seamless.


The only solution I could come up with, for your problem of a click on disable JMenuItem causing it to hide is below:


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. 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.

Anyway this solution works. Enjoy, Boro


I think in Java7 this has been fixed.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜