The JFC Swing Tutorial: A Guide to Constructing GUIs (2nd Edition)
< Day Day Up > |
How to Use Menus
A menu provides a space-saving way to let the user choose one of several options. Other components with which the user can make a one-of-many choice include combo boxes, lists, radio buttons , spinners, and tool bars. If any of your menu items performs an action that is duplicated by another menu item or by a tool-bar button, then in addition to this section you should read How to Use Actions (page 513) in Chapter 9. Menus are unique in that, by convention, they aren't placed with the other components in the UI. Instead, a menu usually appears either in a menu bar or as a popup menu . A menu bar contains one or more menus and has a customary, platform-dependent location ”usually along the top of a window. A popup menu is a menu that is invisible until the user performs a platform-specific mouse action, such as pressing the right mouse button, over a popup-enabled component. The popup menu then appears under the cursor. Figure 31 shows many of Swing's menu- related components: a menu bar, menus, menu items, radio button menu items, check box menu items, and separators. As you can see, a menu item can have either an image or text, or both. You can also specify other properties, such as font and color . Figure 31. The MenuLookDemo example shows many menu-related components.
The Menu Component Hierarchy
As Figure 32 shows, menu items (including menus) are simply buttons. [90] You might be wondering how a menu, if it's only a button, shows its menu items. The answer is that when a menu is activated, it automatically brings up a popup menu that displays the menu items. [90] All the menu-related classes in Figure 32 are in the javax.swing package. You can find their API documentation using a URL such as: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JMenu.html. Figure 32. The inheritance hierarchy for the menu-related classes.
Creating Menus
Note: Because this code has no event handling, the menus do nothing useful except look like they should. If you run the example, you'll notice that despite the lack of custom event handling, menus and submenus appear when they should, and the check boxes and radio buttons respond appropriately when the user chooses them.
//Where the GUI is created: JMenuBar menuBar; JMenu menu, submenu; JMenuItem menuItem; JCheckBoxMenuItem cbMenuItem; JRadioButtonMenuItem rbMenuItem; ... //Create the menu bar. menuBar = new JMenuBar(); setJMenuBar(menuBar); //Build the first menu. menu = new JMenu("A Menu"); menu.setMnemonic(KeyEvent.VK_A); menu.getAccessibleContext().setAccessibleDescription( "The only menu in this program that has menu items"); menuBar.add(menu); //a group of JMenuItems menuItem = new JMenuItem("A text-only menu item" , KeyEvent.VK_T ); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_1, ActionEvent.ALT_MASK)); menuItem.getAccessibleContext().setAccessibleDescription( "This doesn't really do anything"); menu.add(menuItem); menuItem = new JMenuItem("Both text and icon", new ImageIcon("images/middle.gif")); menuItem.setMnemonic(KeyEvent.VK_B); menu.add(menuItem); menuItem = new JMenuItem(new ImageIcon("images/middle.gif")); menuItem.setMnemonic(KeyEvent.VK_D); menu.add(menuItem); //a group of radio button menu items menu.addSeparator(); ButtonGroup group = new ButtonGroup(); rbMenuItem = new JRadioButtonMenuItem("A radio button menu item"); rbMenuItem.setSelected(true); rbMenuItem.setMnemonic(KeyEvent.VK_R); group.add(rbMenuItem); menu.add(rbMenuItem); rbMenuItem = new JRadioButtonMenuItem("Another one"); rbMenuItem.setMnemonic(KeyEvent.VK_O); group.add(rbMenuItem); menu.add(rbMenuItem); //a group of check box menu items menu.addSeparator(); cbMenuItem = new JCheckBoxMenuItem("A check box menu item"); cbMenuItem.setMnemonic(KeyEvent.VK_C); menu.add(cbMenuItem); cbMenuItem = new JCheckBoxMenuItem("Another one"); cbMenuItem.setMnemonic(KeyEvent.VK_H); menu.add(cbMenuItem); //a submenu menu.addSeparator(); submenu = new JMenu("A submenu"); submenu.setMnemonic(KeyEvent.VK_S); menuItem = new JMenuItem("An item in the submenu"); menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_2, ActionEvent.ALT_MASK)); submenu.add(menuItem); menuItem = new JMenuItem("Another item"); submenu.add(menuItem); menu.add(submenu); //Build second menu in the menu bar. menu = new JMenu("Another Menu"); menu.setMnemonic(KeyEvent.VK_N); menu.getAccessibleContext().setAccessibleDescription( "This menu does nothing"); menuBar.add(menu); As the code shows, to set the menu bar for a JFrame , you use the setJMenuBar method. To add a JMenu to a JMenuBar , you use the add(JMenu) method. To add menu items and submenus to a JMenu , you use the add(JMenuItem) method.
Note: Menu items, like other components, can be in at most one container. If you try to add a menu item to a second menu, it will be removed from the first menu before being added to the second. For a way of implementing multiple components that do the same thing, see How to Use Actions (page 513) in Chapter 9.
Other methods in the preceding code include setAccelerator and setMnemonic , which are discussed next in Enabling Keyboard Operation (page 282). The setAccessible- Description method is discussed in How to Support Assistive Technologies (page 519) in Chapter 9. Handling Events from Menu Items
To detect when the user selects a JMenuItem , [92] you can listen for action events (just as you would for a JButton ). To detect when the user selects a JRadioButtonMenuItem , [93] you can listen for either action events or item events, as described in How to Use Radio Buttons (page 311). For JCheckBoxMenuItem s, [94] you generally listen for item events, as described in How to Use Check Boxes (page 163). [92] JMenuItem API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JMenuItem.html. [93] JRadioButtonMenuItem API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JRadioButtonMenuItem.html. [94] JCheckBoxMenuItem API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JCheckBoxMenuItem.html.
Figure 33. MenuDemo adds event listeners to MenuLookDemo .
Here's the code that implements the event handling in MenuDemo : public class MenuDemo ... implements ActionListener, ItemListener { ... //...Where the menu bar's contents are constructed: //for each JMenuItem instance: menuItem.addActionListener(this); ... //for each JRadioButtonMenuItem: rbMenuItem.addActionListener(this); ... //for each JCheckBoxMenuItem: cbMenuItem.addItemListener(this); ... public void actionPerformed(ActionEvent e) { //...Get information from the action event... //...Display it in the text area... } public void itemStateChanged(ItemEvent e) { //...Get information from the item event... //...Display it in the text area... } For examples of handling action and item events, see the button, radio button, and check box sections, as well as the Examples That Use Menus (page 290) section. Enabling Keyboard Operation
Menus support two kinds of keyboard alternatives: mnemonics and accelerators. Mnemonics offer a way to use the keyboard to navigate the menu hierarchy, increasing the accessibility of programs. Accelerators , on the other hand, offer keyboard shortcuts to bypass navigating the menu hierarchy. Mnemonics are for all users; accelerators are for power users. A mnemonic is a key that makes an already visible menu item be chosen . For example, in MenuDemo the first menu has the mnemonic A, and its second menu item has the mnemonic B. This means that, when you run MenuDemo with the Java look and feel, pressing the Alt and A keys makes the first menu appear. While the first menu is visible, pressing the B key (with or without Alt) makes the second menu item be chosen. A menu item generally displays its mnemonic by underlining the first occurrence of the mnemonic character in the menu item's text, as the snapshot in Figure 34 shows. Figure 34. A menu item with the mnemonic character "B."
An accelerator is a key combination that causes a menu item to be chosen, whether or not it's visible. For example, pressing the Alt and 2 keys in MenuDemo makes the first item in the first menu's submenu be chosen, without bringing up any menus. Only leaf menu items ”menus that don't bring up other menus ”can have accelerators. The snapshot in Figure 35 shows how the Java look and feel displays a menu item that has an accelerator. Figure 35. A menu item with the accelerator "Alt+2."
You can specify a mnemonic either when constructing the menu item or with the setMnemonic method. To specify an accelerator, use the setAccelerator method. Here are examples of setting mnemonics and accelerators: //Setting the mnemonic when constructing a menu item: menuItem = new JMenuItem("A text-only menu item", KeyEvent.VK_T); //Setting the mnemonic after creation time: menuItem.setMnemonic(KeyEvent.VK_T); //Setting the accelerator: menuItem.setAccelerator(KeyStroke.getKeyStroke( KeyEvent.VK_T, ActionEvent.ALT_MASK)); As you can see, you set a mnemonic by specifying the KeyEvent [96] constant corresponding to the key the user should press. To specify an accelerator you must use a KeyStroke [97] object, which combines a key (specified by a KeyEvent constant) and a modifier-key mask (specified by an ActionEvent constant). [96] KeyEvent API documentation: http://java.sun.com/j2se/1.4.2/docs/api/java/awt/event/KeyEvent.html. [97] KeyStroke API documentation: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/KeyStroke.html.
Note: Because popup menus, unlike regular menus, aren't always contained by a component, accelerators in popup menu items don't work unless the popup menu is visible.
Bringing up a Popup Menu
To bring up a popup menu ( JPopupMenu ), you must register a mouse listener on each component that the popup menu should be associated with. The mouse listener must detect user requests the popup menu to be brought up. The exact gesture that should bring up a popup menu varies by look and feel. In Microsoft Windows , the user by convention brings up a popup menu by releasing the right mouse button while the cursor is over a component that is popup-enabled. In the Java look and feel, the customary trigger is either pressing the right mouse button (for a popup that goes away when the button is released) or clicking it (for a popup that stays up). [98] [98] In a future release, a new mechanism for automatically triggering popup menus in the appropriate way for the look and feel might be added. You can follow bug #4634626 online at: http://developer.java.sun.com/developer/bugParade/ bugs /4634626.html.
//...where instance variables are declared: JPopupMenu popup; //...where the GUI is constructed: //Create the popup menu. popup = new JPopupMenu(); menuItem = new JMenuItem("A popup menu item"); menuItem.addActionListener(this); popup.add(menuItem); menuItem = new JMenuItem("Another popup menu item"); menuItem.addActionListener(this); popup.add(menuItem); //Add listener to components that can bring up popup menus. MouseListener popupListener = new PopupListener(); output.addMouseListener(popupListener); menuBar.addMouseListener(popupListener); ... class PopupListener extends MouseAdapter { public void mousePressed(MouseEvent e) { maybeShowPopup(e); } public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } Popup menus have a few interesting implementation details. One is that every menu has an associated popup menu. When the menu is activated, it uses its associated popup menu to show its menu items. Another detail is that a popup menu itself uses another component to implement the window containing the menu items. Depending on the circumstances under which the popup menu is displayed, the popup menu might implement its "window" using a lightweight component (such as a JPanel ), a "mediumweight" component (such as a Panel ), or a heavyweight window (something that inherits from Window ). Lightweight popup windows are more efficient than heavyweight windows, but they don't work well if you have any heavyweight components inside your GUI. Specifically, when the lightweight popup's display area intersects the heavyweight component's display area, the heavyweight component is drawn on top. This is one of the reasons we recommend against mixing heavyweight and lightweight components. If you absolutely need to use a heavyweight component in your GUI, then you can invoke JPopupMenu.setLightWeightPopup-Enabled(false) to disable lightweight popup windows. [100] [100] For details, see The Swing Connection article "Mixing Heavy and Light Components" online at: http://java.sun.com/products/jfc/tsc/articles/mixing/index.html. Customizing Menu Layout
Because menus are made up of ordinary Swing components, you can easily customize them. For example, you can add any lightweight component to a JMenu or JMenuBar . And because JMenuBar uses BoxLayout , you can customize a menu bar's layout just by adding invisible components to it. Here's an example of adding a glue component to a menu bar so that the last menu is at the right edge of the menu bar: //...create and add some menus... menuBar.add(Box.createHorizontalGlue()); //...create the rightmost menu... menuBar.add(rightMenu);
Figure 36. A screenshot of the MenuGlueDemo example in which Menu 3 is "glued" to the right side of the menu bar.
Figure 37. A picture of the menu layout that MenuLayoutDemo creates.
The Menu API
Tables 48 through 51 list the commonly used menu constructors and methods. Table 48. Creating and Setting up Menu Bars
Table 49. Creating and Populating Menus
Table 50. Creating, Populating, and Controlling Popup Menus
Table 51. Implementing Menu Items [a]
[a] These methods are inherited from AbstractButton. See The Button API (page 160) for information about other useful methods that AbstractButton provides. Examples That Use Menus
The following examples use menus.
|
< Day Day Up > |