Would You Like to Choose from the Menu?
Contents:
MenuComponent
MenuContainer
MenuShortcut
MenuItem
Menu
CheckboxMenuItem
MenuBar
Putting It All Together
PopupMenu
In Containers, I mentioned that a Frame
can have a menu. Indeed, to offer a menu in the AWT, you have to attach it to a Frame
. With versions 1.0.2 and 1.1, Java does not support menu bars within an applet or any other container. We hope that future versions of Java will allow menus to be used with other containers. Java 1.1 goes partway toward solving this problem by introducing a PopupMenu
that lets you attach context menus to any Component
. Java 1.1 also adds MenuShortcut
events, which represent keyboard accelerator events for menus.
Implementing a menu in a Frame
involves connections among a number of different objects: MenuBar
, Menu
, MenuItem
, and the optional CheckboxMenuItem
. Several of these classes implement the MenuContainer
interface. Once you've created a few menus, you'll probably find the process quite natural, but it's hard to describe until you see what all the objects are. So this chapter describes most of the menu classes first and then shows an example demonstrating their use.
All the components covered in previous chapters were subclasses of Component
. Most of the objects in this chapter subclass MenuComponent
, which encapsulates the common functionality of menu objects. The MenuComponent
class hierarchy is shown in Figure 10.1.
Figure 10.1: MenuComponent class hierarchy
To display a Menu
, you must first put it in a MenuBar
, which you add to a Frame
. (Pop-up menus are different in that they don't need a Frame
.) A Menu
can contain MenuItem
as well as other menus that form submenus. CheckboxMenuItem
is a specialized MenuItem
that (as you might guess) the user can toggle like a Checkbox
. One way to visualize how all these things work together is to imagine a set of curtains. The different MenuItem
components are the fabrics and panels that make up the curtains. The Menus
are the curtains. They get hung from the MenuBar
, which is like a curtain rod. Then you place the MenuBar
curtain rod into the Frame
(the window, in our metaphor), curtains and all.
It might puzzle you that a Menu
is a subclass of MenuItem
, not the other way around. This is because a Menu
can appear on a Menu
just like another MenuItem
, which would not be possible if the hierarchy was the other way around. Figure 10.2 points out the different pieces involved in the creation of a menu: the MenuBar
and various kinds of menu items, including a submenu.
Figure 10.2: The pieces that make up a Menu
MenuComponent
MenuComponent
is an abstract class that is the parent of all menu-related objects. You will never create an instance of the object. Nor are you likely to subclass it yourself--to make the subclass work, you'd have to provide your own peer on every platform where you want the application to run.
MenuComponent Methods
Constructor- public MenuComponent ()--cannot be called directly
- Since
MenuComponent
is an abstract class, you cannot create an instance of the object. This method is called when you create an instance of one of its children.
- public Font getFont ()
- The
getFont()
method retrieves the font associated with theMenuComponent
fromsetFont()
. If the current object's font has not been set, the parent menu's font is retrieved. If there is no parent and the current object's font has not been set,getFont()
returnsnull
. - public void setFont (Font f)
- The
setFont()
method allows you to change the font of the particular menu-related component tof
. When aMenuComponent
is first created, the initial font isnull
, so the parent menu's font is used.
NOTE:
Some platforms do not support changing the fonts of menu items. Where supported, it can make some pretty ugly menus.Names
The name serves as an alternative, nonlocalized reference identifier for menu components. If your event handlers compare menu label strings to an expected value and labels are localized for a new environment, the approach fails.
- public String getName ()
- The
getName()
method retrieves the name of the menu component. Every instance of a subclass ofMenuComponent
is named when it is created. - public void setName (String name)
- The
setName()
method changes the current name of the component toname
.
- public MenuComponentPeer getPeer ()
- The
getPeer()
method returns a reference to theMenuComponent
peer as aMenuComponentPeer
. - public synchronized void removeNotify ()
- The
removeNotify()
method destroys the peer of theMenuComponent
and removes it from the screen.addNotify()
will be specific to the subclass.
Event handling is slightly different between versions. If using the 1.0 event model, use postEvent()
. Otherwise, use dispatchEvent()
to post an event to this MenuComponent
or processEvent()
to receive and handle an event. Remember not to mix versions within your programs.
- public boolean postEvent (Event e)
- The
postEvent()
method postsEvent
e
to theMenuComponent
. The event is delivered to theFrame
at the top of the object hierarchy that contains the selectedMenuComponent
. The only way to capture this event before it gets handed to theFrame
is to override this method. There are no helper functions as there are forComponents
. Find out whichMenuComponent
triggered the event by checkinge.arg
, which contains its label, or((MenuItem)e.target).getName()
for the nonlocalized name of the target.public boolean postEvent (Event e) { // Use getName() vs. e.arg for localization possibility if ("About".equals (((MenuItem)e.target).getName())) playLaughingSound(); // Help request return super.postEvent (e); }
If you override this method, in order for this
Event
to propagate to theFrame
that contains theMenuComponent
, you must call the originalpostEvent()
method (super.postEvent(e)
).The actual value returned by
postEvent()
is irrelevant. - public final void dispatchEvent(AWTEvent e)
- The
dispatchEvent()
method allows you to post new AWT events to this menu component's listeners.dispatchEvent()
tells theMenuComponent
to deal with theAWTEvent e
by calling itsprocessEvent()
method. This method is similar to Java 1.0'spostEvent()
method. Events delivered in this way bypass the system's event queue. It's not clear why you would want to bypass the event queue, except possibly to deliver some kind of high priority event. - protected void processEvent(AWTEvent e)
- The
processEvent()
method receives allAWTEvent
s with a subclass ofMenuComponent
as its target.processEvent()
then passes them along for processing. When you subclass a child class, overridingprocessEvent()
allows you to process all events without having to provide listeners. However, remember to callsuper.processEvent(e)
last to ensure regular functionality is still executed. This is like overridingpostEvent()
using the 1.0 event model.
- public MenuContainer getParent ()
- The
getParent()
method returns the parentMenuContainer
for theMenuComponent
.MenuContainer
is an interface that is implemented byComponent
(in 1.1 only),Frame
,Menu
, andMenuBar
. This means thatgetParent()
could return any one of the four. - protected String paramString ()
- The
paramString()
method ofMenuComponent
helps build up the string to display whentoString()
is called for a subclass. At theMenuComponent
level, the current name of the object is appended to the output. - public String toString ()--can be called by user for subclass
- The
toString()
method at theMenuComponent
level cannot be called directly. ThistoString()
method is called when you call a subclass'stoString()
and the specifics of the subclass is added between the brackets ([ and ]). At this level, the results would be:java.awt.MenuComponent[aname1]