The ability to extend an existing class is one of the most powerful features of object-oriented programming. It allows objects to reuse code defined in the superclasses without having to redefine or recompile the code.
In this section, we will use inheritance to design a ToggleButton as a JButton subclass. As its name suggests, it will toggle its label whenever it is clicked, in addition to carrying out some kind of associated action. It will behave like a light switch, toggling between “on” and “off” as it turns the lights on or off.
By default, a JButton has just a single label. The main idea in our design is that a ToggleButton is a JButton that has two labels, as in Figure 8.4.1.
Note that we give it a constructor method that will allow us to provide the initial values of its labels. Another important feature is that it implements the ActionListener interface, which will enable it to toggle its label whenever it is clicked.
Note how we have defined its constructor. Recall that a subclass constructor must call its superclass constructor. In this case we call super(l1), setting the JButton label through the first of the two ToggleButton labels. This initializes the button’s label. This will be the label that appears on the button when it is first displayed.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ToggleButton extends JButton
implements ActionListener {
private String label1; // Toggle between two labels
private String label2;
public ToggleButton(String l1, String l2) {// Constructor
super(l1); // Use l1 as the default label
label1 = l1;
label2 = l2;
addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
String tempS = label1; // Swap the labels
label1 = label2;
label2 = tempS;
setText(label1);
} // actionPerformed()
} // ToggleButton
Notice also in the constructor that the ToggleButton adds itself as its own ActionListener, so whenever it is clicked, its actionPerformed() method will be invoked.
Swapping two values in memory is a standard programming practice used in lots of different algorithms. It requires a temporary variable, as described in the following algorithm.
It is necessary to use a temporary variable whenever you are swapping two values, of any type, in memory. The temporary variable holds the first value while you overwrite it with the second value.
Now that we have seen that a ToggleButton toggles its label between two values, what about performing an associated action? To do this, we will need multiple event handlers, one to handle the toggling of the button’s label and the other to handle its associated action (Fig 8.4.5).
The implementation of this design is given by LightSwitchTester (Listing 8.4.6). LightSwitchTester extends JFrame and implements the ActionListener interface. The ToggleButton (named lightSwitch) simulate a light switch. Whenever it is pressed, the LightSwitchTester will report whether the light is on or off and the lightSwitch will toggle its label.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class LightSwitchTester extends JFrame
implements ActionListener {
private ToggleButton lightSwitch;
public LightSwitchTester() {
lightSwitch = new ToggleButton ("off","on");
getContentPane().add(lightSwitch);
LightSwitchTester.addActionListener(this);
} // constructor()
public void actionPerformed(ActionEvent e) {
setTitle("The light is " + lightSwitch.getText());
} // actionPerformed()
public static void main(String args[]) {
JFrame f = new LightSwitchTester();
f.setSize(200,200);
f.setVisible(true);
}
} // LightSwitchTester
When lightSwitch is clicked, the program displays the message, “The light is on,” or “The light is off,” in the program’s title bar (Figure 8.4.7). This is a somewhat trivial action but it illustrates that a ToggleButton both toggles its own label and carries out some associated action.
The ToggleButton design satisfies several key design principles of object-oriented programming. First and foremost, it uses inheritance to extend the functionality of the predefined JButton class—the extensibility principle. Secondly, it encapsulates a ToggleButton’s essential behavior within the ToggleButton class itself—the modularity principle. Finally, it hides the mechanism by which a ToggleButton manages its labels—the information-hiding principle.
Suppose you are designing an GUI that plays a card game, and you want a single button that can be used both to deal the cards and to collect the cards. Write a code segment that creates this type of button, adds it to the JFrame, and designates the JFrame as its ActionListener.