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 5

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

In part five in this book excerpt series on Swing menus and toolbars from Java Swing, 2nd Edition, learn how to attach menus to menu bars with the JMenu class.

The JMenu Class

The JMenu class represents the anchored menus attached to a JMenuBar or another JMenu. Menus directly attached to a menu bar are called top-level menus. Submenus, on the other hand, are not attached to a menu bar but to a menu item that serves as its title. This menu item title is typically marked by a right arrow, indicating that its menu appears alongside the menu item if the user selects it. See Figure 14-11.

Figure 14-11. Top-level menu and submenu

Related Reading

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

JMenu is a curious class. It contains a MenuUI delegate, but it uses a ButtonModel for its data model. To see why this is the case, it helps to visualize a menu as two components: a menu item and a pop-up menu. The menu item serves as the title. When it is pressed, it signals the pop-up menu to show itself either below or directly to the right of the menu item. JMenu actually extends the JMenuItem class, which makes it possible to implement the title portion of the menu. This, in effect, makes it a specialized button. On some platforms you can use the mnemonic property of the JMenuItem superclass to define a shortcut for the menu's title and, consequently, the menu. In addition, you can use the enabled property of JMenuItem to disable the menu if desired.

As with pop-up menus, you can add or insert JMenuItem, Component, or Action objects in the pop-up portion of the menu by calling the add( ) and insert( ) methods. You can also add a simple string to the menu; JMenu creates the corresponding JMenuItem object for you internally. The JMenu class assigns an integer index to each menu item and orders them based on the layout manager used for the menu. You can also add separators to the menu by using the addSeparator( ) method.

Warning: You cannot use keyboard accelerators with JMenu objects (top-level or submenu), because accelerators trigger actual program actions, not simply the display of a menu from which actions can be chosen. On some platforms you can use the setMnemonic( ) method to set a shortcut to bring up the menu, but the only universal, reliable approach is to assign keyboard accelerators to the non-submenu JMenuItems that trigger program actions.

You can programmatically cause the submenu to pop up on the screen by setting the popupMenuVisible property to true. Be aware that the pop up does not appear if the menu's title button is not showing.

Figure 14-12 shows the class diagram for the JMenu component.

Figure 14-12. JMenu class diagram

Properties

The JMenu properties are listed in Table 14-8. JMenu uses a JPopupMenu to represent its list of menu items. If you wish to access that underlying menu, you can do so using the popupMenu property. The popupMenuVisible property tracks whether the menu's pop-up portion is currently visible. As noted, setting this to true when the title button is visible causes the pop up to appear. JMenu also contains a selected property, which indicates if the user has selected the title button of the menu. Both properties should mirror each other.

Table 14-8: JMenu properties

Property

Data type

get

is

set

Default value

accessibleContexto

Accessible Context

·

 

 

JMenu.accessibleJMenu( )

component

Component

·

 

 

 

componentOrientation1.4, o

ComponentOrientation

·

 

·

From L&F

delay

int

·

 

·

0

itemCount

int

·

 

 

0

itemi

JMenuItem

·

 

 

null

layouto

LayoutManager

·

 

·

OverlayLayout( )

menuComponentCount

int

·

 

 

0

menuComponenti

Component

·

 

 

null

menuComponents

Component[ ]

·

 

 

 

menuListeners1.4

MenuListener[ ]

·

 

 

 

modelo

ButtonModel

·

 

·

DefaultButtonModel( )

popupMenu

JPopupMenu

·

 

 

 

popupMenuVisible

boolean

 

· ·

false

selected

boolean

 

· ·

false

subElements

MenuElement[ ]

·

 

 

 

tearOffu

boolean

 

·

 

Throws an Error

topLevelMenub, o

boolean

 

·

 

 

UIb

MenuUI

 

 

·

From L&F

UIClassID

String

·

 

 

"MenuUI"

1.4since 1.4, bbound, iindexed, ooverridden, uunimplemented
See also properties from the JMenuItem class (Table 14-4).

The topLevelMenu property has the value true if this JMenu is directly attached to a menu bar and is not a submenu. item is an indexed property that allows access to each of the JMenuItem objects in the menu, while itemCount maintains a count of all of the JMenuItem objects that are present. The delay property specifies the amount of time, in milliseconds, that the underlying menu waits to appear or disappear after receiving the corresponding event. The delay must be set to a positive integer, or setDelay( ) throws an IllegalArgumentException.

The menuComponent property is a more generalized version of the item property; it returns the component at the given index as a Component rather than as a JMenuItem. In addition, the menuComponentCount property retains a count of the menu items, separators, and other components currently in the menu. The menuComponents property lets you access each of the items in the menu, returned as an array of Component objects.

The componentOrientation property is used to accommodate non-Western languages in which text does not flow left to right. JMenu overrides this property in order to properly pass changes on to the JPopupMenu delegate it uses.

Warning: The tearOff property is not yet implemented and is reserved for (increasingly dubious) future use in Swing. Trying to use it throws an Error (rather than something more appropriate like an UnsupportedOp-erationException). Since an Error is supposed to indicate a catastrophic failure of the virtual machine, using this property will almost certainly crash your application.

Constructor

public JMenu(  )
public JMenu(Action a)
public JMenu(String s)
public JMenu(String s, boolean b) 

Initialize a default JMenu. You have the option of specifying a string for the JMenu to display--as well as a boolean for the tearOff property (which is ignored)--or binding it to an Action.

Menu Items

public JMenuItem add(JMenuItem menuItem)
public Component add(Component c) 
public void add(String s)
public JMenuItem add(Action a)

Add various elements to the menus. Objects from both JMenuItem and JComponent can be added, but the latter functions best if it implements the MenuElement interface. If you specify a String as the parameter, a menu item with the appropriate label is created. If you specify an Action, its text and icon properties are used to derive an appropriate JMenuItem, and its text is placed to the right of the icon. It retains its association with the action and is updated to reflect changes to its properties. The resulting JMenuItem is returned, which you can use to alter its formatting.

public void 468addSeparator(  )

Add a separator to the menu. Typically, a separator consists of a single horizontal line drawn across the menu.

public void insert(String s, int index)
public JMenuItem insert(JMenuItem mi, int index)
public JMenuItem insert(Action a, int index)

Insert a specific menu item at a particular index. The index must be positive, or the method throws an IllegalArgumentException. You can pass in a JMenuItem, a String, or an Action to these methods. If you specify a String as the parameter, a menu item with the appropriate label is created. If you specify an Action, its text and icon properties are used to derive an appropriate JMenuItem, and its text is placed to the right of the icon. As usual, the menu retains its association with the action. The resulting JMenuItem is returned, which you can use to alter its formatting. All menu items that were previously at or after the specified position are increased by one.

public void insertSeparator(int index)

Insert a horizontal separator at the position specified by the integer index. The index must be positive, or the method throws an IllegalArgumentException. All menu items' indices that were previously at or after the specified position are increased by one.

public void remove(JMenuItem item)
public void remove(int index)

Remove the menu item that matches the JMenuItem passed in or that currently occupies the specified integer index. If there are no matches (or if the position does not exist), no changes are made to the menu. If the function is successful, all menu items' indices following the removed menu item are reduced by one.

public void removeAll(  )

Remove all of the items from the menu.

Miscellaneous

public void updateUI(  )

Force the default user interface manager to update itself, thus resetting the delegate to display a new MenuUI.

public void setMenuLocation(int x, int y)

Set a custom location at which the menu appears when shown.

public boolean isMenuComponent(Component c)

Determine whether the component c is present anywhere in the menu. This method searches all submenus as well.

public String paramString(  )

Return a String specifying the current state of the menu properties (intended for debugging purposes).

Event

JMenu objects fire a MenuEvent when the user has selected or deselected the menu's title button. The JMenu object contains the standard addChangeListener( ) and removeChangeListener( ) methods for maintaining a list of MenuEvent subscribers.

public void addMenuListener(MenuListener listener)
public void removeMenuListener(MenuListener listener) 

Add or remove a MenuListener from the list of listeners receiving this menu's events.

MenuElement Interface

public void menuSelectionChanged(boolean isIncluded)
public MenuElement[ ] getSubElements(  )
public Component getComponent(  )
public void processKeyEvent(KeyEvent event, MenuElement path[ ], 
   MenuSelectionManager manager)

Implement the MenuElement interface, which is covered later in this chapter.

Working with Menus

Here is a program that demonstrates the use of the JMenu class. In this program, we use Swing's Action class to process the menu events. (We'll also use actions for toolbars later in this chapter.)

//  MenuExample.java
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class MenuExample extends JPanel {

    public JTextPane pane;
    public JMenuBar menuBar;

    public MenuExample(  ) {
        menuBar = new JMenuBar(  );
        JMenu formatMenu = new JMenu("Justify");
        formatMenu.setMnemonic('J');

        MenuAction leftJustifyAction = new MenuAction("Left", 
                                       new ImageIcon("left.gif"));
        MenuAction rightJustifyAction = new MenuAction("Right",
                                        new ImageIcon("right.gif"));
        MenuAction centerJustifyAction = new MenuAction("Center",
                                         new ImageIcon("center.gif"));
        MenuAction fullJustifyAction = new MenuAction("Full",
                                       new ImageIcon("full.gif"));

        JMenuItem item;
        item = formatMenu.add(leftJustifyAction);
        item.setMnemonic('L');
        item = formatMenu.add(rightJustifyAction);
        item.setMnemonic('R');
        item = formatMenu.add(centerJustifyAction);
        item.setMnemonic('C');
        item = formatMenu.add(fullJustifyAction);
        item.setMnemonic('F');

        menuBar.add(formatMenu);
        menuBar.setBorder(new BevelBorder(BevelBorder.RAISED));

    }

    class MenuAction extends AbstractAction {

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

        public void actionPerformed(ActionEvent e) {
            try { pane.getStyledDocument(  ).insertString(0 ,
                  "Action ["+e.getActionCommand(  )+"] performed!\n", null);
            } catch (Exception ex) { ex.printStackTrace(  ); } 
        }
    }

    public static void main(String s[ ]) {

        MenuExample example = new MenuExample(  );
        example.pane = new JTextPane(  );
        example.pane.setPreferredSize(new Dimension(250, 250));
        example.pane.setBorder(new BevelBorder(BevelBorder.LOWERED));

        JFrame frame = new JFrame("Menu Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(example.menuBar);
        frame.getContentPane(  ).add(example.pane, BorderLayout.CENTER);
        frame.pack(  );
        frame.setVisible(true);
    }
}

Our Actions are all instances of the inner class MenuActions. As we add each Action to the menu, it creates an appropriate JMenuItem (with the image left-justified) and returns it to us. This allows us to manipulate the resulting menu item in any way we want; in this case, we add a mnemonic for each item. You can run this program on various platforms to see if they support mnemonics. You shouldn't rely on mnemonics as a key part of your user interface in a program intended for multiple platforms (in fact, you should avoid setting them at all unless you are sure the platform supports them).

The resulting program produces a menu bar with a single menu, as shown in Figure 14-13. The menu contains four menu items and is similar in appearance to the pop-up example. When the user clicks any menu item, Swing generates an ActionEvent to be processed by the actionPerformed( ) method of our MenuAction class. As in the previous examples, this results in the name of the menu item being printed. For variety, we have added a simple JTextPane to display the results of our menu choice, instead of using the system output. See Chapters 19 and 22 and for more information on JTextPane.

Figure 14-13.A set of menu items with icons and mnemonics

The MenuEvent Class

This is a simple event that tells listeners that the target menu has been raised, selected, or canceled. Note that it doesn't tell which one has occurred. The listener defines three separate methods that can be called to deliver the menu event; each one tells exactly what happened.

Constructor

public MenuEvent(Object source)

The constructor takes a reference to the object that fires the event.

The MenuListener Interface

The MenuListener interface, which is the conduit for receiving MenuEvents, specifies three methods. One method is called when the menu is canceled; the other two are called when the title button of the menu is selected or deselected. This interface must be implemented by any listener object that needs to be notified of changes to the menu object.

Methods

public abstract void menuCanceled(MenuEvent e)

This method is called when the menu is canceled or removed from the screen.

public abstract void menuDeselected(MenuEvent e)

This method is called when the target menu's title button is deselected.

public abstract void menuSelected(MenuEvent e)

This method is called when the target menu's title button is selected.

In the next installment, learn about Selectable Menu Items.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.