Java Tips Weblog

  • Blog Stats

    • 2,572,159 hits
  • Categories

  • Archives

Keeping Menus Open

Posted by Darryl Burke on September 12, 2010

The default behavior of menus on all platforms, not just in Java, is for the menu to disappear when any item is selected. But once in a way, one comes across a situation where keeping the menu open could improve the user experience. For example, in the “Quick Preferences” submenu in Opera browser, a user who wants to set more than one option is forced to navigate the menu repeatedly.

Fortunately, the flexibility afforded in terms of extending the JDK classes makes this possible in Java.

While it is more trouble that it is worth to actually prevent a menu from closing when an item is clicked, instantly reopening the menu to the same selection has much the same effect. To do this requires the use of a less known Swing class, MenuSelectionManager. This is the class responsible for setting and clearing menu selections. It can also furnish details of the currently selected menu path.

So, keeping a menu open is a two stage process:

  • Saving the menu path before the item is clicked.
  • Restoring the saved path immediately after the click.

There are many ways in which the first stage might be approached. In these implementations, a ChangeListener added to the menu item’s ButtonModel is used to conditionally save the menu selection path in its stateChanged method when the model is armed and the menu item is showing. Since there can only ever be one menu item with an armed model, some economy is achieved by saving the path to a static field. The saved path is then restored in a minimal override to the doClick method.

Each of the classes provided is furnished with a full set of constructors that call into the constructors of the JDK classes they extend. Any of them can be used as a drop-in replacement in existing code without other modification.

Get The Code

StayOpenMenuItem.java
StayOpenCheckBoxMenuItem.java
StayOpenRadioButtonMenuItem.java

Related Reading

Java API: javax.swing.MenuSelectionManager
Java API: javax.swing.event.ChangeListener
Java API: javax.swing.event.ButtonModel

Java Tutorials: How to Use Menus

17 Responses to “Keeping Menus Open”

  1. Eitan said

    This is great !!!
    I I haven’t seen anything like that !!!
    Thank you very much.

  2. Kleopatra said

    Darryl,

    nice idea :-) The small (?) price to pay is the usual when hiding/reshowing something: there’s an occasional flicker that seems to happen when the popup is extending beyond the parent window (heavyweight).

    Cheers
    Jeanette

    • Darryl Burke said

      Thank you Jeanette. I’m sure you already know this, but since the hiding of the menu is done by the UI delegate, any solution involving not hiding the menu would be LaF dependent. A small flicker when the heavyweight window that houses a popup is re-created is inevitable.

      Darryl

  3. Darryl – what is the licensing on this code?

    • Darryl Burke said

      Like all code published on the blog, these classes are free to use, at your own risk . A link to the blog page in the doc comments or elsewhere would be nice, but is by no means mandatory.

      Darryl

  4. senya said

    forgive me as i’m a noob, but you’ve mentioned all of these classes and haven’t mention how to actually implement them. for someone very new to java i don’t know how to implement that downloaded files. i’ve put them in my project and nothing has changed. do i have to add something to the individual menu items? ie, add a listener of some kind to menu checkboxes?

    • Well, you do need to know enough Java to understand what you’re doing, As a blog is no substitute for a tutorial or training, I suggest you visit the Menus tutorial linked from this page and work your way backwards until you find a suitable starting point for your present level of knowledge.

      Darryl

  5. Lansen said

    Hi Darryl,

    is it possible to do this with popup menu? I’m trying to implement this to DefaultColumnControlPopup (org.jdesktop.swingx.table.ColumnControlPopup) without success. Need some hint

  6. Sehabi said

    when I use a call to method Runtime.getRuntime().exec(cmd) inside the actionPerformed(ActionEvent evt), the classes you provided seems to not work, not sure where it goes wrong …

    • The classes presented here can keep the menu open during several menu selections, but anything that steals focus from the menu will close it. Does your cmd launch another application thus sending your Java application with the stay-open menu to the background?

      Darryl

      • Sehabi said

        in fact I’m just calling the following function (that open a file (word or excel) with MSword or MSexcel), after the document opened the previous menu no more kept open and I have to start selecting choices from the MenuBar (as usual)
        private static void openmyfile(String program_name, String file_name)
        {
        String cmd;
        try {
        cmd = “cmd /C start “+program_name+” “+file_name;
        Runtime.getRuntime().exec(cmd);
        } catch(Exception e1){JOptionPane.showMessageDialog(null,”Error Loading File…”);
        }
        }

      • Like I already said, the menu won’t stay open when you launch another application.

        Darryl

      • Sehabi said

        yes thanks, so I have to find a way to re-execute the last item menu selection…

  7. Taiyang said

    This works great and is very simple to implement, thank you!

    • Jeremy said

      Thanks for this. This worked, but it still presented some flicker. I dabbled a little bit and found the following code further reduces flickering for my JPopupMenu:

      /**
      * This combined with menuSelectionChanged() performs a little
      * hackish voodoo to keep the popup menu visible after you use this checkbox.
      *
      * This is related to, but not the same as, the advice in this article:
      * http://stackoverflow.com/questions/3759379/how-to-prevent-jpopupmenu-disappearing-when-checking-checkboxes-in-it
      */
      @Override
      public void doClick(int pressTime)
      {
      super.doClick(pressTime);

      JPopupMenu popup = (JPopupMenu)menuSelection[0];
      if(!popup.isShowing()) {
      popup.setVisible(true);
      MenuSelectionManager.defaultManager().setSelectedPath(menuSelection);
      }
      }

      /**
      * This combined with doClick() performs a little
      * hackish voodoo to keep the popup menu visible after you use this checkbox.
      */
      @Override
      public void menuSelectionChanged(boolean isIncluded)
      {
      super.menuSelectionChanged(isIncluded);
      if(!isIncluded) {
      menuSelection = MenuSelectionManager.defaultManager().getSelectedPath();
      }
      }

Leave a comment