ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button O'Reilly Book Excerpts: Java Swing, 2nd Edition

Java Swing: Menus and Toolbars, Part 3

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

In part three in this book excerpt series on Swing menus and toolbars from Java Swing, 2nd Edition, learn about the JMenuItem class.

The JMenuItem Class

Before discussing menus, we should introduce the JMenuItem class. Figure 14-6 shows the class diagram for the JMenuItem component.

Figure 14-6. JMenuItem class diagram

Related Reading

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

A JMenuItem serves as a wrapper for strings and images to be used as elements in a menu. The JMenuItem class is essentially a specialized button and extends the AbstractButton class. Its behavior, however, is somewhat different from standalone buttons. When the mouse pointer is dragged over a menu item, Swing considers the menu item to be selected. If the user releases the mouse button while over the menu item, it is considered to be chosen and should perform its action.

There is an unfortunate conflict in terminology here. Swing considers a menu item selected when the mouse moves over it, as updated by the MenuSelectionManager and classes that implement the MenuElement interface. On the other hand, Swing considers a button selected when it remains in one of two persistent states, such as a checkbox button remaining in the checked state until clicked again. So when a menu item is selected, its button model is really armed. Conversely, when a menu item is deselected, its button model is disarmed. Finally, when the user releases the mouse button over the menu item, the button is considered to be clicked, and the AbstractButton's doClick( ) method is invoked.

Menu Item Shortcuts

Menu items can take both keyboard accelerators and (on some platforms) mnemonics. Mnemonics are an artifact of buttons; they appear as a single underline below the character that represents the shortcut. Keyboard accelerators, on the other hand, are inherited from JComponent. With menu items, they have the unique side effect of appearing in the menu item. (Their exact appearance and location is up to the L&F.) Figure 14-7 shows both mnemonics and keyboard accelerators.

Figure 14-7. Mnemonics and keyboard accelerators

Keyboard accelerators and mnemonics perform the same function: users can abbreviate common GUI actions with keystrokes. However, a mnemonic can be activated only when the button (or menu item) it represents is visible on the screen. Menu item keyboard accelerators can be invoked any time the application has the focus-- whether the menu item is visible or not. Also, as noted, accelerators work on all platforms and all L&Fs while mnemonics are less universal. Menus may be assigned both at once.

Let's look at programming both cases. Keyboard accelerators typically use a variety of keystrokes: function keys, command keys, or an alphanumeric key in combination with one or more modifiers (e.g., Shift, Ctrl, or Alt). All of these key combinations can be represented by the javax.swing.KeyStroke class, but only some of them are appropriate for the platform and L&F in use. Hence, you can assign a keyboard accelerator to a menu item by setting its accelerator property with a KeyStroke object configured using the default toolkit's menuShortcutKeyMask property, as follows:

JMenuItem m = new JMenuItem("Copy");
m.setAccelerator(KeyStroke.getKeyStroke('C',
    Toolkit.getDefaultToolkit(  ).getMenuShortcutKeyMask(  ), false));

Under Metal, this sets the accelerator to Ctrl-C, which is the letter C typed in combination with the Ctrl key. The accelerator appears at the right side of the menu item (though again, the position is up to the L&F). The KeyStroke class is covered in more detail in Chapter 27.

The second, less universal, way to set a shortcut is through the mnemonic property of the AbstractButton superclass:

JMenuItem mi = new JMenuItem("Copy");
mi.setMnemonic('C');

The mnemonic property underlines the character you pass into the setMnemonic( ) method. Note that mnemonic characters cannot take modifiers; they are simple letters. Be sure to use a letter that exists in the menu item's label. Otherwise, nothing is underlined, and the user will not know how to activate the keyboard shortcut. Also be sure to set up mnemonics only if you're running on a platform and L&F that support them.

As of SDK 1.4, you can use the displayedMnemonicIndex property to cope with menu items containing multiple copies of the character you're using as a mnemonic, if it makes more sense for a later instance to be underlined (for example, the common Save As menu item in which the uppercase "A" should get the underline). To achieve this, once you set up the mnemonic, call setDisplayedMnemonicIndex with a value of 5.

Images

In Swing, menu items can contain (or consist entirely of) icons. This can be a visual aid if the icon can convey the intended meaning more clearly. You can pass an Icon object to the constructor of the JMenuItem class as follows:

JMenu menu = new JMenu("Justify");

// The first two menu items contain text and an image. The third
// uses only the image.
menu.add(new JMenuItem("Center", new ImageIcon("center.gif")));
menu.add(new JMenuItem("Right", new ImageIcon("right.gif")));
menu.add(new JMenuItem(new ImageIcon("left.gif")));

By default, the text is placed to the left of the image. This is shown on the left in Figure 14-8. As you can see, this often misaligns the images to the right of the text, especially if there is a menu item consisting only of an image. If the menu item images are all the same width, you can improve the appearance of your menus by altering the text's position using the setHorizontalTextAlignment( ) method:

JMenu menu = new JMenu("Justify");

// The first two menu items contain text and an image. The third
// uses only the image. The text is now set to the right.
JMenuItem item1= new JMenuItem("Center", new ImageIcon("center.gif")));
item1.setHorizontalTextAlignment(SwingConstants.RIGHT);
JMenuItem item2= new JMenuItem("Right", new ImageIcon("right.gif")));
item2.setHorizontalTextAlignment(SwingConstants.RIGHT);

// Now add the menu items to the menu.
menu.add(item1);
menu.add(item2);
menu.add(new JMenuItem(new ImageIcon("left.gif")));

Figure 14-8. Image and text placement in menu items

This positions the text on the other side of the images, as shown on the right of Figure 14-8. You can trace the setHorizontalTextAlignment( ) method up the class hierarchy to the AbstractButton class. As we mentioned before, the JMenuItem class is a button object with respect to its text and image. AbstractButton contains a setVerticalTextAlignment( ) method as well, so if the accompanying image is taller than the menu item text, you can use this method to set the text's vertical position as well. (See the AbstractButton class in Chapter 5 and the OverlayLayout class in Chapter 11 for more information about alignment with menu items and buttons.) The image is placed to the left of the text if you construct a menu item from an Action object (more on this later in the chapter).

Java supports image transparency, so if you require some parts of an image to be transparent, you can specify a "transparent" color in the GIF file (many paint programs allow you to do this), or you can create a specialized color filter that seeks out specific pixel colors and changes their opacity before passing the resulting Image onto the menus. The former is much easier.

Event Handling

There are a number of ways to process events from menu items. Because menu items inherit ActionEvent functionality from AbstractButton, one approach is to assign an action command to each menu item (this is often done automatically with named components) and attach all of the menu items to the same ActionListener. Then, in the actionPerformed( ) method of the listener, use the event's getActionCommand( ) method to obtain the action command of the menu item generating the event. This tells the listener which menu item has been clicked, allowing it to react accordingly. This is the approach used in IntroExample.java earlier in this chapter and PopupMenuExample.java, which is discussed later.

Alternatively, you can register a separate ActionListener class with each menu item, which takes the guesswork out of determining the menu item selected. However, Swing allows you to go a step further. The most object-oriented approach is to create a specialized Action class that corresponds to each of the tasks a user might request of your application. This lets you bundle the code for each program action together with the action's name, icon, keystrokes, and other attributes in one place. You can then use this Action to create the menu item, which automatically sets the item's text, image, accelerator, and so on.

This technique is particularly powerful if you want to be able to invoke the same action in multiple ways (such as from a toolbar as well as a menu). You can use the same Action instance to create the menu item and toolbar button, and they'll both have appropriate labels and appearances. If the application needs to disable the action because it's not currently appropriate, calling setEnabled on the Action instance automatically updates all user interface elements associated with the action (thus dimming both your menu item and toolbar button). Similarly, changing other attributes of the action, such as its name or icon, automatically updates any associated user-interface components.

Although prior to SDK 1.3 it wasn't possible to construct a JMenuItem from an Action directly, adding the Action to a JMenu or JPopupMenu had the same effect: the menu would create and configure an appropriate JMenuItem for you.

Pages: 1, 2, 3

Next Pagearrow