Using Menus with Frames

Menus are an integral part of GUIs. Menus allow the user to perform actions without unnecessarily cluttering a GUI with extra components. In Swing GUIs, menus can be attached only to objects of the classes that provide method setJMenuBar. Two such classes are JFrame and JApplet. The classes used to declare menus are JMenuBar, JMenu, JMenuItem, JCheckBoxMenuItem and class JRadioButtonMenuItem.

Look-and-Feel Observation 22.2

Menus simplify GUIs because components can be hidden within them. These components will only be visible when the user looks for them by selecting the menu.

Class JMenuBar (a subclass of JComponent) contains the methods necessary to manage a menu bar, which is a container for menus. Class JMenu (a subclass of javax.swing.JMenuItem) contains the methods necessary for managing menus. Menus contain menu items and are added to menu bars or to other menus as submenus. When a menu is clicked, it expands to show its list of menu items.

Class JMenuItem (a subclass of javax.swing.AbstractButton) contains the methods necessary to manage menu items. A menu item is a GUI component inside a menu that, when selected, causes an action event. A menu item can be used to initiate an action or it can be a submenu that provides more menu items from which the user can select. Submenus are useful for grouping related menu items in a menu.

Class JCheckBoxMenuItem (a subclass of javax.swing.JMenuItem) contains the methods necessary to manage menu items that can be toggled on or off. When a JCheckBoxMenuItem is selected, a check appears to the left of the menu item. When the JCheckBoxMenuItem is selected again, the check is removed.

Class JRadioButtonMenuItem (a subclass of javax.swing.JMenuItem) contains the methods necessary to manage menu items that can be toggled on or off like JCheckBoxMenuItems. When multiple JRadioButtonMenuItems are maintained as part of a ButtonGroup, only one item in the group can be selected at a given time. When a JRadioButtonMenuItem is selected, a filled circle appears to the left of the menu item. When another JRadioButtonMenuItem is selected, the filled circle of the previously selected menu item is removed.

The application in Fig. 22.5 and Fig. 22.6 demonstrates various menu items. The application also demonstrates how to specify special characters called mnemonics that can provide quick access to a menu or menu item from the keyboard. Mnemonics can be used with all subclasses of javax.swing.AbstractButton.

Figure 22.5. JMenus and mnemonics.

(This item is displayed on pages 1012 - 1016 in the print version)

1 // Fig. 22.5: MenuFrame.java 2 // Demonstrating menus. 3 import java.awt.Color; 4 import java.awt.Font; 5 import java.awt.BorderLayout; 6 import java.awt.event.ActionListener; 7 import java.awt.event.ActionEvent; 8 import java.awt.event.ItemListener; 9 import java.awt.event.ItemEvent; 10 import javax.swing.JFrame; 11 import javax.swing.JRadioButtonMenuItem; 12 import javax.swing.JCheckBoxMenuItem; 13 import javax.swing.JOptionPane; 14 import javax.swing.JLabel; 15 import javax.swing.SwingConstants; 16 import javax.swing.ButtonGroup; 17 import javax.swing.JMenu; 18 import javax.swing.JMenuItem; 19 import javax.swing.JMenuBar; 20 21 public class MenuFrame extends JFrame 22 { 23 private final Color colorValues[] = 24 { Color.BLACK, Color.BLUE, Color.RED, Color.GREEN }; 25 private JRadioButtonMenuItem colorItems[]; // color menu items 26 private JRadioButtonMenuItem fonts[]; // font menu items 27 private JCheckBoxMenuItem styleItems[]; // font style menu items 28 private JLabel displayJLabel; // displays sample text 29 private ButtonGroup fontButtonGroup; // manages font menu items 30 private ButtonGroup colorButtonGroup; // manages color menu items 31 private int style; // used to create style for font 32 33 // no-argument constructor set up GUI 34 public MenuFrame() 35 { 36 super ( "Using JMenus" ); 37 38 JMenu fileMenu = new JMenu( "File" ); // create file menu 39 fileMenu.setMnemonic( 'F' ); // set mnemonic to F 40 41 // create About... menu item 42 JMenuItem aboutItem = new JMenuItem( "About..." ); 43 aboutItem.setMnemonic( 'A' ); // set mnemonic to A 44 fileMenu.add( aboutItem ); // add about item to file menu 45 aboutItem.addActionListener( 46 47 new ActionListener() // anonymous inner class 48 { 49 // display message dialog when user selects About... 50 public void actionPerformed( ActionEvent event ) 51 { 52 JOptionPane.showMessageDialog( MenuFrame.this, 53 "This is an example of using menus", 54 "About", JOptionPane.PLAIN_MESSAGE ); 55 } // end method actionPerformed 56 } // end anonymous inner class 57 ); // end call to addActionListener 58 59 JMenuItem exitItem = new JMenuItem( "Exit" ); // create exit item 60 exitItem.setMnemonic( 'x' ); // set mnemonic to x 61 fileMenu.add( exitItem ); // add exit item to file menu 62 exitItem.addActionListener( 63 64 new ActionListener() // anonymous inner class 65 { 66 // terminate application when user clicks exitItem 67 public void actionPerformed( ActionEvent event ) 68 { 69 System.exit( 0 ); // exit application 70 } // end method actionPerformed 71 } // end anonymous inner class 72 ); // end call to addActionListener 73 74 JMenuBar bar = new JMenuBar(); // create menu bar 75 setJMenuBar( bar ); // add menu bar to application 76 bar.add( fileMenu ); // add file menu to menu bar 77 78 JMenu formatMenu = new JMenu( "Format" ); // create format menu 79 formatMenu.setMnemonic( 'r' ); // set mnemonic to r 80 81 // array listing string colors 82 String colors[] = { "Black", "Blue", "Red", "Green" }; 83 84 JMenu colorMenu = new JMenu( "Color" ); // create color menu 85 colorMenu.setMnemonic( 'C' ); // set mnemonic to C 86 87 // create radiobutton menu items for colors 88 colorItems = new JRadioButtonMenuItem[ colors.length ]; 89 colorButtonGroup = new ButtonGroup(); // manages colors 90 ItemHandler itemHandler = new ItemHandler(); // handler for colors 91 92 // create color radio button menu items 93 for ( int count = 0 ; count < colors.length; count++ ) 94 { 95 colorItems[ count ] = 96 new JRadioButtonMenuItem( colors[ count ] ); // create item 97 colorMenu.add( colorItems[ count ] ); // add item to color menu 98 colorButtonGroup.add( colorItems[ count ] ); // add to group 99 colorItems[ count ].addActionListener( itemHandler ); 100 } // end for 101 102 colorItems[ 0 ].setSelected( true ); // select first Color item 103 104 formatMenu.add( colorMenu ); // add color menu to format menu 105 formatMenu.addSeparator(); // add separator in menu 106 107 // array listing font names 108 String fontNames[] = { "Serif", "Monospaced", "SansSerif" }; 109 JMenu fontMenu = new JMenu( "Font" ); // create font menu 110 fontMenu.setMnemonic( 'n' ); // set mnemonic to n 111 112 // create radiobutton menu items for font names 113 fonts = new JRadioButtonMenuItem[ fontNames.length ]; 114 fontButtonGroup = new ButtonGroup(); // manages font names 115 116 // create Font radio button menu items 117 for ( int count = 0 ; count < fonts.length; count++ ) 118 { 119 fonts[ count ] = new JRadioButtonMenuItem( fontNames[ count ] ); 120 fontMenu.add( fonts[ count ] ); // add font to font menu 121 fontButtonGroup.add( fonts[ count ] ); // add to button group 122 fonts[ count ].addActionListener( itemHandler ); // add handler 123 } // end for 124 125 fonts[ 0 ].setSelected( true ); // select first Font menu item 126 fontMenu.addSeparator(); // add separator bar to font menu 127 128 String styleNames[] = { "Bold", "Italic" }; // names of styles 129 styleItems = new JCheckBoxMenuItem[ styleNames.length ]; 130 StyleHandler styleHandler = new StyleHandler(); // style handler 131 132 // create style checkbox menu items 133 for ( int count = 0 ; count < styleNames.length; count++ ) 134 { 135 styleItems[ count ] = 136 new JCheckBoxMenuItem( styleNames[ count ] ); // for style 137 fontMenu.add( styleItems[ count ] ); // add to font menu 138 styleItems[ count ].addItemListener( styleHandler ); // handler 139 } // end for 140 141 formatMenu.add( fontMenu ); // add Font menu to Format menu 142 bar.add( formatMenu ); // add Format menu to menu bar 143 144 // set up label to display text 145 displayJLabel = new JLabel( "Sample Text", SwingConstants.CENTER ); 146 displayJLabel.setForeground( colorValues[ 0 ] ); 147 displayJLabel.setFont( new Font( "Serif", Font.PLAIN, 72 ) ); 148 149 getContentPane().setBackground( Color.CYAN ); // set background 150 add( displayJLabel, BorderLayout.CENTER ); // add displayJLabel 151 } // end MenuFrame constructor 152 153 // inner class to handle action events from menu items 154 private class ItemHandler implements ActionListener 155 { 156 // process color and font selections 157 public void actionPerformed( ActionEvent event ) 158 { 159 // process color selection 160 for ( int count = 0 ; count < colorItems.length; count++ ) 161 { 162 if ( colorItems[ count ].isSelected() ) 163 { 164 displayJLabel.setForeground( colorValues[ count ] ); 165 break ; 166 } // end if 167 } // end for 168 169 // process font selection 170 for ( int count = 0 ; count < fonts.length; count++ ) 171 { 172 if ( event.getSource() == fonts[ count ] ) 173 { 174 displayJLabel.setFont( 175 new Font( fonts[ count ].getText(), style, 72 ) ); 176 } // end if 177 } // end for 178 179 repaint(); // redraw application 180 } // end method actionPerformed 181 } // end class ItemHandler 182 183 // inner class to handle item events from check box menu items 184 private class StyleHandler implements ItemListener 185 { 186 // process font style selections 187 public void itemStateChanged( ItemEvent e ) 188 { 189 style = 0 ; // initialize style 190 191 // check for bold selection 192 if ( styleItems[ 0 ].isSelected() ) 193 style += Font.BOLD; // add bold to style 194 195 // check for italic selection 196 if ( styleItems[ 1 ].isSelected() ) 197 style += Font.ITALIC; // add italic to style 198 199 displayJLabel.setFont( 200 new Font( displayJLabel.getFont().getName(), style, 72 ) ); 201 repaint(); // redraw application 202 } // end method itemStateChanged 203 } // end class StyleHandler 204 } // end class MenuFrame

Figure 22.6. Test class for MenuFrame.

(This item is displayed on page 1017 in the print version)

1 // Fig. 22.6: MenuTest.java 2 // Testing MenuFrame. 3 import javax.swing.JFrame; 4 5 public class MenuTest 6 { 7 public static void main( String args[] ) 8 { 9 MenuFrame menuFrame = new MenuFrame(); // create MenuFrame 10 menuFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 11 menuFrame.setSize( 500, 200 ); // set frame size 12 menuFrame.setVisible( true ); // display frame 13 } // end main 14 } // end class MenuTest  

Class MenuFrame (Fig. 22.5) declares the GUI components and event handling for the menu items. Most of the code in this application appears in the class's constructor (lines 34151).

Lines 3876 set up the File menu and attach it to the menu bar. The File menu contains an About... menu item that displays a message dialog when the menu item is selected and an Exit menu item that can be selected to terminate the application.

Line 38 creates a JMenu and passes to the constructor the string "File" as the name of the menu. Line 39 uses JMenu method setMnemonic (inherited from class AbstractButton) to indicate that F is the mnemonic for this menu. Pressing the Alt key and the letter F opens the menu, just as clicking the menu name with the mouse would. In the GUI, the mnemonic character in the menu's name is displayed with an underline. (See the screen captures in Fig. 22.6)

Look-and-Feel Observation 22.3

Mnemonics provide quick access to menu commands and button commands through the keyboard.

Look-and-Feel Observation 22.4

Different mnemonics should be used for each button or menu item. Normally, the first letter in the label on the menu item or button is used as the mnemonic. If several buttons or menu items start with the same letter, choose the next most prominent letter in the name (e.g., x is commonly chosen for a button or menu item called Exit).

Lines 4243 create JMenuItem aboutItem with the text "About..." and set its mnemonic to the letter A. This menu item is added to fileMenu at line 44 with JMenu method add. To access the About... menu item through the keyboard, press the Alt key and letter F to open the File menu, then press A to select the About... menu item. Lines 4756 create an ActionListener to process aboutItem's action event. Lines 5254 display a message dialog box. In most prior uses of showMessageDialog, the first argument was null. The purpose of the first argument is to specify the parent window that helps determine where the dialog box will be displayed. If the parent window is specified as null, the dialog box appears in the center of the screen. Otherwise, it appears centered over the specified parent window. In this example, the program specifies the parent window with MenuTest.thisthe this reference of the MenuTest object. When using the this reference in an inner class, specifying this by itself refers to the inner-class object. To reference the outer-class object's this reference, qualify this with the outer-class name and a dot (.).

Dialog boxes are typically modal. A modal dialog box does not allow any other window in the application to be accessed until the dialog box is dismissed. The dialogs displayed with class JOptionPane are modal dialogs. Class JDialog can be used to create your own modal or nonmodal dialogs.

Lines 5972 create menu item exitItem, set its mnemonic to x, add it to fileMenu and register an ActionListener that terminates the application when the user selects exitItem.

Lines 7476 create the JMenuBar, attach it to the application window with JFrame method setJMenuBar and use JMenuBar method add to attach the fileMenu to the menu bar.

Common Programming Error 22.3

Forgetting to set the menu bar with JFrame method setJMenuBar results in the menu bar not being displayed on the JFrame.

Look-and-Feel Observation 22.5

Menus appear left to right in the order that they are added to a JMenuBar.

Lines 7879 create menu formatMenu and set its mnemonic to r. (F is not used because that is the File menu's mnemonic.)

Lines 8485 create menu colorMenu (this will be a submenu in the Format menu) and set its mnemonic to C. Line 88 creates JRadioButtonMenuItem array colorItems, which refers to the menu items in colorMenu. Line 89 creates ButtonGroup colorGroup, which will ensure that only one of the menu items in the Color submenu is selected at a time. Line 90 creates an instance of inner class ItemHandler (declared at lines 154181) that responds to selections from the Color and Font submenus (discussed shortly). The for statement at lines 93100 creates each JRadioButtonMenuItem in array colorItems, adds each menu item to colorMenu and to colorGroup and registers the ActionListener for each menu item.

Line 102 invokes AbstractButton method setSelected to select the first element in array colorItems. Line 104 adds colorMenu as a submenu of formatMenu. Line 105 invokes JMenu method addSeparator to add a horizontal separator line to the menu.

Look-and-Feel Observation 22.6

A submenu is created by adding a menu as a menu item in another menu. When the mouse is positioned over a submenu (or the submenu's mnemonic is pressed), the submenu expands to show its menu items.

Look-and-Feel Observation 22.7

Separators can be added to a menu to group menu items logically.

Look-and-Feel Observation 22.8

Any lightweight GUI component (i.e., a component that is a subclass of JComponent) can be added to a JMenu or to a JMenuBar.

Lines 108126 create the Font submenu and several JRadioButtonMenuItems and select the first element of JRadioButtonMenuItem array fonts. Line 129 creates a JCheckBoxMenuItem array to represent the menu items for specifying bold and italic styles for the fonts. Line 130 creates an instance of inner class StyleHandler (declared at lines 184203) to respond to the JCheckBoxMenuItem events. The for statement at lines 133139 creates each JCheckBoxMenuItem, adds each menu item to fontMenu and registers the ItemListener for each menu item. Line 141 adds fontMenu as a submenu of formatMenu. Line 142 adds the formatMenu to bar (the menu bar).

Lines 145147 create a JLabel for which the Format menu items control the font, font color and font style. The initial foreground color is set to the first element of array colorValues (Color.BLACK) by invoking JComponent method setForeground, and the initial font is set to Serif with PLAIN style and 72-point size. Line 149 sets the background color of the window's content pane to cyan, and line 150 attaches the JLabel to the CENTER of the content pane's BorderLayout.

ItemHandler method actionPerformed (lines 157180) uses two for statements to determine which font or color menu item generated the event and sets the font or color of the JLabel displayLabel, respectively. The if condition at line 162 uses AbstractButton method isSelected to determine the selected JRadioButtonMenuItem. The if condition at line 172 invokes the event object's getSource method to get a reference to the JRadioButtonMenuItem that generated the event. Line 175 invokes AbstractButton method getText to obtain the name of the font from the menu item.

The program calls StyleHandler method itemStateChanged (lines 187202) if the user selects a JCheckBoxMenuItem in the fontMenu. Lines 192 and 196 determine whether either or both of the JCheckBoxMenuItems are selected and use their combined state to determine the new style of the font.

Категории