2

I have attached some JCheckBoxMenuItems to my JMenu in place of a JMenuItem. When the user clicks on the JMenu, it displays the JCheckBoxMenuItems. Once the user selects one of the boxes from the JCheckBoxMenuItem, the list of JCheckBoxMenuItems disappears, ie closes. How can I override the default action for this so that it remains open (so they can select/deselect more than one box at once) until the user clicks somewhere outside of the JCheckBoxMenuItems?

bob dylan
  • 647
  • 1
  • 10
  • 25
  • The two methods I've seen is to either to implement your own UI delegate (not really a good solution) or implement your own `JMenuItem` and override the `processMouseEvent`, again, not pretty – MadProgrammer Dec 02 '15 at 00:02

1 Answers1

8

The two basic ways I've seen to get this to work is to either supply your own UI delegate, which isn't pretty and would require you to supply a UI delegate for each platform you want to support or override the processMouseEvent of the JMenuItem (or JCheckBoxMenuItem in your case).

For example...

Static menu items

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JMenuBar mb = new JMenuBar();
                JMenu menu = new JMenu("Lots-o-stuff");
                mb.add(menu);

                menu.add(new MyMenuItem("Apples"));
                menu.add(new MyMenuItem("Pears"));
                menu.add(new MyMenuItem("Bananas"));

                JFrame frame = new JFrame("Testing");
                frame.setJMenuBar(mb);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public class MyMenuItem extends JCheckBoxMenuItem {

        public MyMenuItem() {
        }

        public MyMenuItem(Icon icon) {
            super(icon);
        }

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

        public MyMenuItem(Action a) {
            super(a);
        }

        public MyMenuItem(String text, Icon icon) {
            super(text, icon);
        }

        public MyMenuItem(String text, boolean b) {
            super(text, b);
        }

        public MyMenuItem(String text, Icon icon, boolean b) {
            super(text, icon, b);
        }

        @Override
        protected void processMouseEvent(MouseEvent evt) {
            if (evt.getID() == MouseEvent.MOUSE_RELEASED && contains(evt.getPoint())) {
                doClick();
                setArmed(true);
            } else {
                super.processMouseEvent(evt);
            }
        }
    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • That's cool... now can you make it toggle the checkmarks on/off? – geowar Oct 13 '17 at 22:51
  • @geowar Change the call to setArmed – MadProgrammer Oct 13 '17 at 23:21
  • You'll need to override `processKeyEvent` also to handle keyboard-based selection. Alternative solution that works regardless of how item is selected is provided in following article: [https://tips4java.wordpress.com/2010/09/12/keeping-menus-open/] – ewh May 24 '21 at 17:05