Buttons that Maintain State
The Swing GUI components contain three types of state buttonsJToggleButton, JCheckBox and JRadioButtonthat have on/off or true/false values. Classes JCheckBox and JRadioButton are subclasses of JToggleButton (Fig. 11.14). A JRadioButton is different from a JCheckBox in that normally several JRadioButtons are grouped together, and are mutually exclusiveonly one in the group can be selected at any time. We first discuss class JCheckBox. The next two subsections also demonstrate that an inner class can access the members of its top-level class.
11.9.1. JCheckBox
The application of Fig. 11.17 and Fig. 11.18 uses two JCheckBox objects to select the desired font style of the text displayed in a JTextField. When selected, one applies a bold style and the other an italic style. If both are selected, the style of the font is bold and italic. When the application initially executes, neither JCheckBox is checked (i.e., they are both false), so the font is plain. Class CheckBoxTest (Fig. 11.18) contains the main method that executes this application.
Figure 11.17. JCheckBox buttons and item events.
(This item is displayed on pages 537 - 538 in the print version)
1 // Fig. 11.17: CheckBoxFrame.java 2 // Creating JCheckBox buttons. 3 import java.awt.FlowLayout; 4 import java.awt.Font; 5 import java.awt.event.ItemListener; 6 import java.awt.event.ItemEvent; 7 import javax.swing.JFrame; 8 import javax.swing.JTextField; 9 import javax.swing.JCheckBox; 10 11 public class CheckBoxFrame extends JFrame 12 { 13 private JTextField textField; // displays text in changing fonts 14 private JCheckBox boldJCheckBox; // to select/deselect bold 15 private JCheckBox italicJCheckBox; // to select/deselect italic 16 17 // CheckBoxFrame constructor adds JCheckBoxes to JFrame 18 public CheckBoxFrame() 19 { 20 super( "JCheckBox Test" ); 21 setLayout( new FlowLayout() ); // set frame layout 22 23 // set up JTextField and set its font 24 textField = new JTextField( "Watch the font style change", 20 ); 25 textField.setFont( new Font( "Serif", Font.PLAIN, 14 ) ); 26 add( textField ); // add textField to JFrame 27 28 boldJCheckBox = new JCheckBox( "Bold" ); // create bold checkbox 29 italicJCheckBox = new JCheckBox( "Italic" ); // create italic 30 add( boldJCheckBox ); // add bold checkbox to JFrame 31 add( italicJCheckBox ); // add italic checkbox to JFrame 32 33 // register listeners for JCheckBoxes 34 CheckBoxHandler handler = new CheckBoxHandler(); 35 boldJCheckBox.addItemListener( handler ); 36 italicJCheckBox.addItemListener( handler ); 37 } // end CheckBoxFrame constructor 38 39 // private inner class for ItemListener event handling 40 private class CheckBoxHandler implements ItemListener 41 { 42 private int valBold = Font.PLAIN; // controls bold font style 43 private int valItalic = Font.PLAIN; // controls italic font style 44 45 // respond to checkbox events 46 public void itemStateChanged( ItemEvent event ) 47 { 48 // process bold checkbox events 49 if ( event.getSource() == boldJCheckBox ) 50 valBold = 51 boldJCheckBox.isSelected() ? Font.BOLD : Font.PLAIN; 52 53 // process italic checkbox events 54 if ( event.getSource() == italicJCheckBox ) 55 valItalic = 56 italicJCheckBox.isSelected() ? Font.ITALIC : Font.PLAIN; 57 58 // set text field font 59 textField.setFont( 60 new Font( "Serif", valBold + valItalic, 14 ) ); 61 } // end method itemStateChanged 62 } // end private inner class CheckBoxHandler 63 } // end class CheckBoxFrame |
Figure 11.18. Test class for CheckBoxFrame.
(This item is displayed on page 538 in the print version)
1 // Fig. 11.18: CheckBoxTest.java 2 // Testing CheckBoxFrame. 3 import javax.swing.JFrame; 4 5 public class CheckBoxTest 6 { 7 public static void main( String args[] ) 8 { 9 CheckBoxFrame checkBoxFrame = new CheckBoxFrame(); 10 checkBoxFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 11 checkBoxFrame.setSize( 275, 100 ); // set frame size 12 checkBoxFrame.setVisible( true ); // display frame 13 } // end main 14 } // end class CheckBoxTest
|
After the JTextField is created and initialized (Fig. 11.17, line 24), line 25 uses method setFont (inherited by JTextField indirectly from class Component) to set the font of the JTextField to a new object of class Font (package java.awt). The new Font is initialized with "Serif" (a generic font name representing a font such as Times and is supported on all Java platforms), Font.PLAIN style and 14-point size. Next, lines 2829 create two JCheckBox objects. The string passed to the JCheckBox constructor is the checkbox label that appears to the right of the JCheckBox by default.
When the user clicks a JCheckBox, an ItemEvent occurs. This event can be handled by an ItemListener object, which must implement method itemStateChanged. In this example, the event handling is performed by an instance of private inner class CheckBoxHandler (lines 4062). Lines 3436 create an instance of class CheckBoxHandler and register it with method addItemListener as the listener for both the JCheckBox objects.
Lines 4243 declare instance variables for the inner class CheckBoxHandler. Together, these variables represent the font style for the text displayed in the JTextField. Initially both are Font.PLAIN to indicate that the font is not bold and is not italic. Method itemStateChanged (lines 4661) is called when the user clicks the bold or the italic JCheckBox. The method uses event.getSource() to determine which JCheckBox the user clicked. If it was the boldJCheckBox, line 51 uses JCheckBox method isSelected to determine if the JCheckBox is selected (i.e., it is checked). If the checkbox is selected, local variable valBold is assigned Font.BOLD; otherwise, it is assigned Font.PLAIN. A similar statement executes if the user clicks the italicJCheckBox. If the italicJCheckBox is selected, local variable valItalic is assigned Font.ITALIC; otherwise, it is assigned Font.PLAIN. Lines 5960 change the font of the JTextField, using the same font name and point size. The sum of valBold and valItalic represents the JTextField's new font style. Each of the Font constants represents a unique value. Font.PLAIN has the value 0, so if both valBold and valItalic are set to Font.PLAIN, the font will have the plain style. If one of the values is Font.BOLD or Font.ITALIC, the font will be bold or italic accordingly. If one is BOLD and the other is ITALIC, the font will be both bold and italic.
Relationship Between an Inner Class and Its Top-Level Class
You may have noticed that class CheckBoxHandler used variables boldJCheckBox (Fig. 11.17, lines 49 and 51), italicJCheckBox (lines 54 and 56) and textField (line 59) even though these variables are not declared in the inner class. An inner class has a special relationship with its top-level classthe inner class is allowed to access directly all the instance variables and methods of the top-level class. Method itemStateChanged (line 4661) of class CheckBoxHandler uses this relationship to determine which JCheckBox is the event source, to determine the state of a JCheckBox and to set the font on the JTextField. Notice that none of the code in inner class CheckBoxHandler requires a reference to the top-level class object.
11.9.2. JRadioButton
Radio buttons (declared with class JRadioButton) are similar to check boxes in that they have two statesselected and not selected (also called deselected). However, radio buttons normally appear as a group in which only one button can be selected at a time (see output of Fig. 11.20). Selecting a different radio button forces all others to be deselected. Radio buttons are used to represent mutually exclusive options (i.e., multiple options in the group cannot be selected at the same time). The logical relationship between radio buttons is maintained by a ButtonGroup object (package javax.swing), which itself is not a GUI component. A ButtonGroup object organizes a group of buttons and is not itself displayed in a user interface. Rather, the individual JRadioButton objects from the group are displayed in the GUI.
Common Programming Error 11.3
Adding a ButtonGroup object (or an object of any other class that does not derive from Component) to a container results in a compilation error. |
The application of Fig. 11.19 and Fig. 11.20 is similar to that of Fig. 11.17 and Fig. 11.18. The user can alter the font style of a JTextField's text. The application uses radio buttons that permit only a single font style in the group to be selected at a time. Class RadioButtonTest (Fig. 11.20) contains the main method that executes this application.
Figure 11.19. JRadioButtons and ButtonGroups.
(This item is displayed on pages 540 - 541 in the print version)
1 // Fig. 11.19: RadioButtonFrame.java 2 // Creating radio buttons using ButtonGroup and JRadioButton. 3 import java.awt.FlowLayout; 4 import java.awt.Font; 5 import java.awt.event.ItemListener; 6 import java.awt.event.ItemEvent; 7 import javax.swing.JFrame; 8 import javax.swing.JTextField; 9 import javax.swing.JRadioButton; 10 import javax.swing.ButtonGroup; 11 12 public class RadioButtonFrame extends JFrame 13 { 14 private JTextField textField; // used to display font changes 15 private Font plainFont; // font for plain text 16 private Font boldFont; // font for bold text 17 private Font italicFont; // font for italic text 18 private Font boldItalicFont; // font for bold and italic text 19 private JRadioButton plainJRadioButton; // selects plain text 20 private JRadioButton boldJRadioButton; // selects bold text 21 private JRadioButton italicJRadioButton; // selects italic text 22 private JRadioButton boldItalicJRadioButton; // bold and italic 23 private ButtonGroup radioGroup; // buttongroup to hold radio buttons 24 25 // RadioButtonFrame constructor adds JRadioButtons to JFrame 26 public RadioButtonFrame() 27 { 28 super( "RadioButton Test" ); 29 setLayout( new FlowLayout() ); // set frame layout 30 31 textField = new JTextField( "Watch the font style change", 25 ); 32 add( textField ); // add textField to JFrame 33 34 // create radio buttons 35 plainJRadioButton = new JRadioButton( "Plain", true ); 36 boldJRadioButton = new JRadioButton( "Bold", false ); 37 italicJRadioButton = new JRadioButton( "Italic", false ); 38 boldItalicJRadioButton = new JRadioButton( "Bold/Italic", false ); 39 add( plainJRadioButton ); // add plain button to JFrame 40 add( boldJRadioButton ); // add bold button to JFrame 41 add( italicJRadioButton ); // add italic button to JFrame 42 add( boldItalicJRadioButton ); // add bold and italic button 43 44 // create logical relationship between JRadioButtons 45 radioGroup = new ButtonGroup(); // create ButtonGroup 46 radioGroup.add( plainJRadioButton ); // add plain to group 47 radioGroup.add( boldJRadioButton ); // add bold to group 48 radioGroup.add( italicJRadioButton ); // add italic to group 49 radioGroup.add( boldItalicJRadioButton ); // add bold and italic 50 51 // create font objects 52 plainFont = new Font( "Serif", Font.PLAIN, 14 ); 53 boldFont = new Font( "Serif", Font.BOLD, 14 ); 54 italicFont = new Font( "Serif", Font.ITALIC, 14 ); 55 boldItalicFont = new Font( "Serif", Font.BOLD + Font.ITALIC, 14 ); 56 textField.setFont( plainFont ); // set initial font to plain 57 58 // register events for JRadioButtons 59 plainJRadioButton.addItemListener( 60 new RadioButtonHandler( plainFont ) ); 61 boldJRadioButton.addItemListener( 62 new RadioButtonHandler( boldFont ) ); 63 italicJRadioButton.addItemListener( 64 new RadioButtonHandler( italicFont ) ); 65 boldItalicJRadioButton.addItemListener( 66 new RadioButtonHandler( boldItalicFont ) ); 67 } // end RadioButtonFrame constructor 68 69 // private inner class to handle radio button events 70 private class RadioButtonHandler implements ItemListener 71 { 72 private Font font; // font associated with this listener 73 74 public RadioButtonHandler( Font f ) 75 { 76 font = f; // set the font of this listener 77 } // end constructor RadioButtonHandler 78 79 // handle radio button events 80 public void itemStateChanged( ItemEvent event ) 81 { 82 textField.setFont( font ); // set font of textField 83 } // end method itemStateChanged 84 } // end private inner class RadioButtonHandler 85 } // end class RadioButtonFrame |
Figure 11.20. Test class for RadioButtonFrame.
(This item is displayed on page 542 in the print version)
1 // Fig. 11.20: RadioButtonTest.java 2 // Testing RadioButtonFrame. 3 import javax.swing.JFrame; 4 5 public class RadioButtonTest 6 { 7 public static void main( String args[] ) 8 { 9 RadioButtonFrame radioButtonFrame = new RadioButtonFrame(); 10 radioButtonFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 11 radioButtonFrame.setSize( 300, 100 ); // set frame size 12 radioButtonFrame.setVisible( true ); // display frame 13 } // end main 14 } // end class RadioButtonTest
|
Lines 3542 in the constructor (Fig. 11.19) create four JRadioButton objects and add them to the JFrame. Each JRadioButton is created with a constructor call like that in line 35. This constructor specifies the label that appears to the right of the JRadioButton by default and the initial state of the JRadioButton. A TRue second argument indicates that the JRadioButton should appear selected when it is displayed.
Line 45 instantiates ButtonGroup object radioGroup. This object is the "glue" that forms the logical relationship between the four JRadioButton objects and allows only one of the four to be selected at a time. It is possible that no JRadioButtons in a ButtonGroup are selected, but this can only occur if no preselected JRadioButtons are added to the ButtonGroup and the user has not selected a JRadioButton yet. Lines 4649 use ButtonGroup method add to associate each of the JRadioButtons with radioGroup. If more than one selected JRadioButton object is added to the group, the selected one that was added first will be selected when the GUI is displayed.
JRadioButtons, like JCheckBoxes, generate ItemEvents when they are clicked. Lines 5966 create four instances of inner class RadioButtonHandler (declared at lines 7084). In this example, each event listener object is registered to handle the ItemEvent generated when the user clicks a particular JRadioButton. Notice that each RadioButtonHandler object is initialized with a particular Font object (created in lines 5255).
Class RadioButtonHandler (line 7084) implements interface ItemListener so it can handle ItemEvents generated by the JRadioButtons. The constructor stores the Font object it receives as an argument in the event-listener object's instance variable font (declared at line 72). When the user clicks a JRadioButton, radioGroup turns off the previously selected JRadioButton and method itemStateChanged (line 8083) sets the font in the JTextField to the Font stored in the JRadioButton's corresponding event-listener object. Notice that line 82 of inner class RadioButtonHandler uses the top-level class's textField instance variable to set the font.