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 2

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 2 of this book excerpt on Swing menus and toolbars from Java Swing, 2nd Edition, learn about menu bar selection models, beginning with the JMenuBar class.

Menu Bar Selection Models

In all GUI environments, menu components allow only one selection to be made at a time. Swing is no exception. Swing provides a data model that menu bars and menus can use to emulate this behavior: the SingleSelectionModel.

The SingleSelectionModel Interface

Objects implementing the SingleSelectionModel interface do exactly what its name suggests: they maintain an array of possible selections and allow one element in the array to be chosen at a time. The model holds the index of the selected element. If a new element is chosen, the model resets the index representing the chosen element and fires a ChangeEvent to each of the registered listeners.

Properties

Objects implementing the SingleSelectionModel interface contain the properties shown in Table 14-1. The selected property is a boolean that tells if there is a selection. The selectedIndex property is an integer index that represents the currently selected item.

Table 14-1: SingleSelectionModel properties

Property

Data type

get

is

set

Default value

selected

boolean

 

·

 

 

selectedIndex

int

·

 

·

 

Events

Objects implementing the SingleSelectionModel interface must fire a ChangeEvent (not a PropertyChangeEvent) when the object modifies its selectedIndex property, i.e., when the selection has changed. The interface contains the standard addChangeListener( ) and removeChangeListener( ) methods for maintaining a list of ChangeEvent listeners.

Add or remove the specified ChangeListener from the list of listeners receiving this model's change events:

void addChangeListener(ChangeListener listener)
void removeChangeListener(ChangeListener listener)

Method

The SingleSelectionModel interface contains one other method.

Clear the selection value, forcing the selected property to return false:

public void clearSelection(  )

The DefaultSingleSelectionModel Class

Swing provides a simple default implementation of the SingleSelectionModel interface in the DefaultSingleSelectionModel class.

Properties

DefaultSingleSelectionModel contains just the properties required by the SingleSelectionModel interface, as shown in Table 14-2. The selectedIndex property is an integer index that represents the currently selected item. The default value of -1 indicates that there is no selection. The selected property is a boolean that returns true if the selectedIndex is anything other than -1, and false otherwise.

Table 14-2: DefaultSingleSelectionModel properties

Property

Data type

get

is

set

Default value

selected

boolean

 

·

 

false

selectedIndex

int

·

 

·

-1

Events and methods

The DefaultSingleSelectionModel object provides all the events and methods specified by the SingleSelectionModel interface discussed earlier.

The JMenuBar Class

Swing's JMenuBar class supersedes the AWT MenuBar class. This class creates a horizontal menu bar component with zero or more menus attached to it. JMenuBar uses the DefaultSingleSelectionModel as its data model because the user can raise, or activate, only one of its menus at a given time. Once the mouse pointer leaves that menu, the class removes the menu from the screen (or cancels it, in Swing lingo), and all menus again become eligible to be raised. Figure 14-4 shows the class hierarchy for the JMenuBar component.

Figure 14-4. JMenuBar class diagram
Figure 14-4

You can add JMenu objects to the menu bar with the add( ) method of the JMenuBar class. JMenuBar then assigns an integer index based on the order in which the menus were added. The menu bar displays the menus from left to right on the bar according to their assigned index. In theory, there is one exception: the help menu. You are supposed to be allowed to mark one menu as the help menu; the location of the help menu is up to the L&F. In practice, trying to do this results in JMenuBar throwing an Error.

Menu Bar Placement

You can attach menu bars to Swing frames or applets in one of two ways. First, you can use the setJMenuBar( ) method of JFrame, JDialog, JApplet, or JInternalFrame:

JFrame frame = new JFrame("Menu");
JMenuBar menuBar = new JMenuBar(  );

// Attach the menu bar to the frame.
frame.setJMenuBar(menuBar);

The setJMenuBar( ) method is analogous to the setMenuBar( ) method of java.awt.Frame. Like its predecessor, setJMenuBar( ) allows the L&F to determine the location of the menu (typically, it anchors the menu bar to the top of a frame, adjusting the frame's internal Insets accordingly). Both JApplet and JDialog contain a setJMenuBar( ) method-- this means that you can add menu bars to both applets and dialogs. Either way, be sure not to confuse the setJMenuBar( ) method with the older setMenuBar( ) method of AWT when working with Swing menus, or the compiler complains bitterly.

If your application is running on a Macintosh, the Mac L&F can be configured to place menu bars at the top of the screen, where Mac users expect to find them. Setting the system property com.apple.macos.useScreenMenuBar to true activates this behavior. It's disabled by default because most Java programs do not expect this behavior, and they must be coded properly to deal with it. Notably, the Aqua Human Interface Guidelines require that the menu bar is always visible. If your application has any frames that lack menu bars, whenever one of these gains focus, it causes the menu bar to disappear, much to the user's consternation. The most common way of dealing with this is to write a menu factory that generates an identical menu bar for each frame your application uses. Although this is a little extra work, the familiarity and comfort it brings your Mac users is probably worth it.

The second way to add a menu bar is much less common. Recall that the JMenuBar class extends JComponent. This means it can be positioned by a Swing layout manager like other Swing components. For example, we could replace the call to setJMenuBar( ) with the following code:

menuBar.setBorder(new BevelBorder(BevelBorder.RAISED)); 
frame.getContentPane(  ).add(menuBar, BorderLayout.SOUTH);

This places the menu bar at the bottom of the frame, as shown in Figure 14-5. (Note that we set a beveled border around the menu bar to help outline its location.) It would even be possible to add two or three menu bars in different locations. Swing does not require a single menu bar to be anchored to the top of a frame. Because they extend JComponent, multiple menu bars can be positioned anywhere inside a container.

Figure 14-5. JMenuBar positioned as a Swing component
Figure 14-5

TIP: You have to add at least one named menu to a menu bar for it to gain any thickness. Otherwise, it appears as a thin line--similar to a separator.

Of course, you'd never actually want to do this without a very compelling reason. It robs the L&F of its opportunity to place the menu bar in the appropriate location. Moving something as fundamental as a menu bar is almost certain to cause confusion and usability challenges for your users; having multiple menu bars would be baffling.

Properties

The properties of the JMenuBar class are shown in Table 14-3. menu is an indexed property that references each JMenu attached to the menu bar. The read-only menuCount property maintains a count of these attached menus. Remember that the single selection model allows only one menu to be activated at a time. If any menu is currently activated, the selected property returns true; otherwise, the property returns false. The componentAtIndex property accesses the menu associated with the given index. It is similar to the indexed menu property, except the contents are cast to a Component. If there is no component associated with that index, the getComponentAtIndex( ) accessor returns null. The component property returns a reference to this (i.e., the menu bar itself); subElements returns an array consisting of the menus on the menu bar.

Table 14-3: JMenuBar properties

Property

Data type

get

is

set

Default value

accessibleContexto

AccessibleContext

·

 

 

JMenuBar.AccessibleJMenuBar( )

borderPaintedb

boolean

 

·

·

true

component

Component

·

 

 

this

componentAtIndexi

Component

·

 

 

true

helpMenuu

JMenu

·

 

·

Throws an Error

layouto

LayoutManager

·

 

·

BoxLayout(X_AXIS)

marginb

Insets

·

 

·

null

menuCount

int

·

 

 

0

menui

JMenu

·

 

 

null

selected

boolean

 

·

 

false

selectionModelb

SingleSelectionModel

·

 

·

DefaultSingleSelectionModel( )

subElements

MenuElement[ ]

·

 

 

 

UIb

MenuBarUI

·

 

·

From L&F

UIClassIDo

String

·

 

 

"MenuBarUI"

bbound, iindexed, ooverridden, uunimplemented
See also properties from the JComponent class (Table 3-6).

The margin property controls the amount of space between the menu bar's border and its menus while the borderPainted property can be used to suppress the painting of the menu bar's border even if the border property has a non-null value. Setting borderPainted to false prevents the normal painting of the border. For more information about Swing borders, see Chapter 13.

WARNING: The helpMenu property is supposed to allow you to designate one JMenu as the help menu (which has a special location in some operating systems), but this property has never been implemented, and using it throws an Error even in SDK 1.4. You can take advantage of the fact that the menu bar uses a BoxLayout to insert "glue" to position your (ordinary) help menu at the right edge when appropriate, but this shifts the burden of knowing when to do that (based on the current L&F) to your code, which is unfortunate.

Constructor

public JMenuBar(  )

Create and initialize an empty JMenuBar object.

Menu

public JMenu add(JMenu menu)

You can use this method to attach a JMenu to the menu bar set. Because of the BoxLayout of JMenuBar, menus are displayed on the menu bar from left to right in the order that you add( ) them. The method returns a reference to the JMenu that was passed in, allowing you to string together calls--for example, menubar.add(menu).add(menuitem).

Miscellaneous

public int getComponentIndex(Component c)

Return the index associated with the component reference passed in. If there is no match to the component, the method returns a -1. The only type of component it makes sense to pass in is JMenu.

public void setSelected(Component c)

Force the menu bar (and its associated model) to select a particular menu, which fires a ChangeEvent in the menu bar's single selection model. This method, for example, is called when a mnemonic key for a particular menu is pressed. Note that this is different than the boolean selected property listed in Table 14-3.

public void updateUI(  )

Force the UIManager to refresh the L&F of the component, based on the current UI delegate.

JMenuBar also implements the methods specified by the MenuElement interface, which is covered later in this chapter.


Return to ONJava.com.