Multi level menus in Flamingo

May 10th, 2010

I was recently asked how to create multi-level menus with Flamingo command menu buttons. There is nothing preventing you from creating arbitrary hierarchies of menus – and you can do this even in the stable 4.2 release. The latest 5.0dev drop of the library brings small improvements for mixing menu buttons with and without icons, and here is a small code sample to create a two-level menu:

public class MultiLevelMenu extends JFrame {

   public MultiLevelMenu() {
      super("Multi level menu");

      JCommandButton main = new JCommandButton("click me");
      main.setCommandButtonKind(CommandButtonKind.POPUP_ONLY);
      main.setDisplayState(CommandButtonDisplayState.MEDIUM);
      main.setFlat(false);

      // first level menu
      main.setPopupCallback(new PopupPanelCallback() {
         @Override
         public JPopupPanel getPopupPanel(JCommandButton commandButton) {
            JCommandPopupMenu result = new JCommandPopupMenu();

            result.addMenuButton(new JCommandMenuButton("Copy",
                  new edit_copy()));
            result.addMenuButton(new JCommandMenuButton("Cut",
                  new edit_cut()));
            result.addMenuButton(new JCommandMenuButton("Paste",
                  new edit_paste()));

            result.addMenuSeparator();

            JCommandMenuButton second = new JCommandMenuButton("Find", null);
            second.setCommandButtonKind(CommandButtonKind.POPUP_ONLY);
            // second level
            second.setPopupCallback(new PopupPanelCallback() {
               @Override
               public JPopupPanel getPopupPanel(
                     JCommandButton commandButton) {
                  JCommandPopupMenu result = new JCommandPopupMenu();

                  result.addMenuButton(new JCommandMenuButton("Find",
                        new edit_find()));
                  result.addMenuButton(new JCommandMenuButton(
                        "Find replace", new edit_find_replace()));

                  return result;
               }
            });
            second.setPopupOrientationKind(CommandButtonPopupOrientationKind.SIDEWARD);
            result.addMenuButton(second);

            return result;
         }
      });

      this.setLayout(new FlowLayout(FlowLayout.LEADING));
      this.add(main);

      this.setSize(300, 200);
      this.setLocationRelativeTo(null);
      this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         @Override
         public void run() {
            SubstanceLookAndFeel.setSkin(new GeminiSkin());
            JFrame.setDefaultLookAndFeelDecorated(true);

            new MultiLevelMenu().setVisible(true);
         }
      });
   }
}

And this is how it looks like:

https://flamingo.dev.java.net/release-info/5.0/multi-level-menus.png

Couple of things to note:

  • It’s the same JCommandButton.setPopupCallback API that is used to create all menu levels
  • By default the popups are displayed below the originator component (unlike the core Swing menus). Use JCommandButton.setPopupOrientationKind API passing the SIDEWARD enum value to it to recreate the core Swing behavior.