ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


O'Reilly Book Excerpts: Java Swing, 2nd Edition

Java Swing: Menus and Toolbars, Part 1

Related Reading

Java Swing
By Marc Loy, Robert Eckstein, Dave Wood, James Elliott, Brian Cole

by Robert Eckstein, Marc Loy, Dave Wood, James Elliott, Brian Cole

In part one in this excerpt on menus and toolbars from O'Reilly Java Swing, 2nd Edition, get an introduction to Swing menus.

This chapter discusses Swing menus and toolbars. Menus are the richer and more flexible of the two, so they encompass most of the chapter. They tend to be the first thing users explore in learning a new application, so it's fitting that Swing provides a great deal of freedom in laying out menu components.

Toolbars allow you to group buttons, combo boxes, and other elements together in repositionable panels; these tools can assist the user in performing many common tasks. You can add any component to a Swing toolbar, even non-Swing components. In addition, Swing allows the toolbar to be dragged from the frame and positioned inside a child window for convenience.

Introducing Swing Menus

Swing menu components are subclasses of JComponent. Consequently, they have all the benefits of a Swing component, and you can treat them as such with respect to layout managers and containers.

Here are some notable features of the Swing menu system:

Swing provides familiar menu separators, checkbox menu items, pop-up menus, and submenus for use in your applications. In addition, Swing menus support keyboard accelerators and "underline" style (mnemonic) shortcuts, and you can attach menu bars to the top of Swing frames with a single function that adjusts the frame insets accordingly. On the Macintosh, your application can be configured so that this method places the menu bar at the top of the screen, where users expect to find it. Figure 14-1 defines the various elements that make up the menu system in Swing.

Figure 14-1. The elements of the Swing menu system
fig 14-1

Note that not all platforms support underline-style mnemonics. Notably, on the Macintosh (which has never provided this sort of user interface) mnemonics do not appear at all in the system menu bar, and though they are visible in the actual menus, they do not work in either place. If your application uses mnemonics, you should consider grouping the code to set them up into a separate method that is invoked only when running on a platform that supports them.

All platforms do support accelerators (shortcuts) but have different conventions about the key used to invoke them. You can take advantage of the Toolkit method getMenuShortcutKeyMask to always use the right key.

Menu Hierarchy

The class diagram for Swing menus is shown in Figure 14-2.

Figure 14-2. Swing menu diagram
fig 14-2

You might be surprised to find AbstractButton in the hierarchy, but menus and menu items have many features in common with Swing buttons. For example, menu items can be highlighted (when the mouse pointer passes over them), they can be clicked to indicate that the user has made a choice, they can be disabled and grayed like buttons, and they can be assigned action commands to assist with event handling. JCheckBoxMenuItem and JRadioButtonMenuItem can even be toggled between two selection states. Since Swing menu components share much of the functionality of Swing buttons, it is appropriate and efficient that they inherit from AbstractButton.

It may also seem surprising that JMenu inherits from JMenuItem, instead of vice-versa. This is because each JMenu contains an implicit menu item that serves as the title of the menu. You'll often hear this part of the menu called the title button. When the user presses or drags the mouse cursor over the title button, the corresponding menu appears. Note, however, that menus do not have to be anchored to a menu bar. You can embed them in other menus, where they act as submenus. This means that the title button must be able to act as a menu item, which would not be possible if the hierarchy was reversed. We discuss this behavior in more detail when we cover the JMenu class later in this chapter.

Almost all of the menu classes implement the MenuElement interface. The MenuElement interface outlines standardized methods that dictate how each Swing menu component behaves when it encounters user input, such as keyboard or mouse events. Swing menu classes typically process these mouse and keyboard events and pass notifications to the component delegates, which handle any necessary redrawing of the component. These methods work in tandem with the MenuSelectionManager class. While you rarely need to implement the MenuElement interface, it helps to know how it works. We show how to implement this interface later in the chapter.

Getting Your Feet Wet

Okay, it's time to jump in. Here is a flashy program that introduces much of the basic Swing menu functionality:

// IntroExample.java
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class IntroExample extends JMenuBar {

   String[ ] fileItems = new String[ ] { "New", "Open", "Save", "Exit" };
   String[ ] editItems = new String[ ] { "Undo", "Cut", "Copy", "Paste" };
   char[ ] fileShortcuts = { 'N','O','S','X' };
   char[ ] editShortcuts = { 'Z','X','C','V' };

   public IntroExample(  ) {

      JMenu fileMenu = new JMenu("File");
      JMenu editMenu = new JMenu("Edit");
      JMenu otherMenu = new JMenu("Other");
      JMenu subMenu = new JMenu("SubMenu");
      JMenu subMenu2 = new JMenu("SubMenu2");

      // Assemble the File menus with mnemonics.
      ActionListener printListener = new ActionListener(  ) {
         public void actionPerformed(ActionEvent event) {
            System.out.println("Menu item [" + event.getActionCommand(  ) +
                               "] was pressed.");
         }
      };
      for (int i=0; i < fileItems.length; i++) {
         JMenuItem item = new JMenuItem(fileItems[i], fileShortcuts[i]);
         item.addActionListener(printListener);
         fileMenu.add(item);
      }

      // Assemble the File menus with keyboard accelerators.
      for (int i=0; i < editItems.length; i++) {
         JMenuItem item = new JMenuItem(editItems[i]);
         item.setAccelerator(KeyStroke.getKeyStroke(editShortcuts[i],
              Toolkit.getDefaultToolkit(  ).getMenuShortcutKeyMask(  ), false));
         item.addActionListener(printListener);
         editMenu.add(item);
      }

      // Insert a separator in the Edit menu in Position 1 after "Undo".
      editMenu.insertSeparator(1);

      // Assemble the submenus of the Other menu.
      JMenuItem item;
      subMenu2.add(item = new JMenuItem("Extra 2"));
      item.addActionListener(printListener);
      subMenu.add(item = new JMenuItem("Extra 1"));
      item.addActionListener(printListener);
      subMenu.add(subMenu2);

      // Assemble the Other menu itself.
      otherMenu.add(subMenu);
      otherMenu.add(item = new JCheckBoxMenuItem("Check Me"));
      item.addActionListener(printListener);
      otherMenu.addSeparator(  );
      ButtonGroup buttonGroup = new ButtonGroup(  );
      otherMenu.add(item = new JRadioButtonMenuItem("Radio 1"));
      item.addActionListener(printListener);
      buttonGroup.add(item);
      otherMenu.add(item = new JRadioButtonMenuItem("Radio 2"));
      item.addActionListener(printListener);
      buttonGroup.add(item);
      otherMenu.addSeparator(  );
      otherMenu.add(item = new JMenuItem("Potted Plant", 
                           new ImageIcon("image.gif")));
      item.addActionListener(printListener);

      // Finally, add all the menus to the menu bar.
      add(fileMenu);
      add(editMenu);
      add(otherMenu);
   }

   public static void main(String s[ ]) {
      JFrame frame = new JFrame("Simple Menu Example");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setJMenuBar(new IntroExample(  ));
      frame.pack(  );
      frame.setVisible(true);
   }
}

This example creates a menu bar with three simple menus, attaching mnemonics to the menu items of the File menu and keyboard accelerators to the menu items of the Edit menu. Figure 14-3 shows a mosaic of the different menus that the program produces. It also shows how the Edit menu looks on two different platforms, with the proper accelerator key (Control or Command) used on each.

Figure 14-3. A sample of Swing menu effects
fig 14-3

In the third menu, we've enhanced the last item with a GIF image of a potted plant. In addition, the first menu item in the Other menu is actually a submenu that pops out to a second submenu, underscoring the recursive nature of menus. If you select any of the menus, you are rewarded with a simple text output that tells you what you clicked:

Menu item [New] was pressed.
Menu item [Radio 1] was pressed.

Don't worry if you do not understand all the classes and methods at this point. We will examine each menu component in detail shortly.

In the next installment, learn about menu bar selection models.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.