How to prevent a disabled JMenuItem from hiding the menu when being clicked?
Asked Answered
I

7

6

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." );
}
Idolater answered 6/3, 2011 at 13:9 Comment(4)
can you show code you have written?Purpurin
@harshit: I have attached a code sample for how i initialize the JMenuItem. I do not do any action in the click event ... This menu hiding is just the default Java behavior.Idolater
"I have attached a code sample..". For better help sooner, post an SSCCE (pscode.org/sscce.html) rather than code snippets.Maintop
@Andrew: Thanks Andrew. I will do that next time.Idolater
L
0

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!

Loutitia answered 17/4, 2011 at 11:24 Comment(5)
@jmendeth ... Is there a similar solution for JComboBox disabled items ?Idolater
@Idolater yes, just make your own JComboBox class and copy the processMouseEvent method into it. Then replace any JComboBox with your class. If you want, I can post an example.Loutitia
@jmendeth ... I am not getting that ... Shouldn't the processMouseEvent be applied to the JComboBox items & not the JcomboBox itself ? ... I'd be grateful if you write me an example.Idolater
@Idolater sorry, I didn't express correctly. Yes, the processMouseEvent must be applied to all the items in the popup. In this case, the ComboBox items.Loutitia
@jmendeth ... Emmmm, Thanks anyway.Idolater
P
0

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.

Purpurin answered 7/3, 2011 at 19:35 Comment(3)
Sorry, I do not get what you mean by setVisible(false) ?Idolater
you can do saveMenuItem.setVisible(false)Purpurin
But i want to make it visible and disabled ! If i clicked a disabled item no action will occur, but the menu will close. Try it.Idolater
S
0

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.

Seroka answered 8/3, 2011 at 9:57 Comment(0)
C
0

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.

Charlsiecharlton answered 8/3, 2011 at 15:7 Comment(0)
H
0

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.

Hysteresis answered 10/3, 2011 at 10:35 Comment(0)
P
0

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

Platen answered 5/4, 2011 at 19:33 Comment(0)
L
0

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!

Loutitia answered 17/4, 2011 at 11:24 Comment(5)
@jmendeth ... Is there a similar solution for JComboBox disabled items ?Idolater
@Idolater yes, just make your own JComboBox class and copy the processMouseEvent method into it. Then replace any JComboBox with your class. If you want, I can post an example.Loutitia
@jmendeth ... I am not getting that ... Shouldn't the processMouseEvent be applied to the JComboBox items & not the JcomboBox itself ? ... I'd be grateful if you write me an example.Idolater
@Idolater sorry, I didn't express correctly. Yes, the processMouseEvent must be applied to all the items in the popup. In this case, the ComboBox items.Loutitia
@jmendeth ... Emmmm, Thanks anyway.Idolater
P
0

I think in Java7 this has been fixed.

Picnic answered 28/11, 2013 at 14:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.