Return to index

Part 3

One way to allow the light to be switched both on and off is to provide two buttons - one for on and one for off. This is what we will do in Example3. Most of the source code for Example3 is the same as Example2.

Here is the code for the Example3 constructor:

public Example3() {

LightBox light=new LightBox();

 

JButton button=new JButton("On");

button.addActionListener(light);

 

JButton button2=new JButton("Off");

button2.addActionListener(light);

 

add(button);

add(button2);

add(new JLabel(" ")); // to create a space

add(light);

}

 

We employ a second button object with a different ActionCommand property (equal to the button's displayed text by default). Now our LightBox object listens to two buttons, both of which send an ActionEvent object but with different ActionCommand properties.

Run Example3 to confirm that you can now switch the light on and off at will.

But wouldn't it be nice if we could use just one button to toggle the light on and off! This is what we will do next.

The first approach we will take is to write some code to achieve a toggling effect - click once for on, click again for off. We will put this in our new Example4 class. So this time class Example4 will be the ActionListener for the button; it will perform the toggling logic and then tell the LightBox to switch on or off as required.

Here is the source code for class Example4:

package projects.tjioo4;

 

import projects.guicomps.*;

import java.awt.event.*;

import javax.swing.*;

 

public class Example4 extends JPanel implements ActionListener {

private boolean on;

private LightBox2 light;

 

// Constructor

public Example4() {

light=new LightBox2();

JButton button=new JButton("Light");

button.addActionListener(this);

add(button);

add(new JLabel(" "));

add(light);

}

 

public void actionPerformed(ActionEvent e) {

on=!on; // the toggling logic

light.setOn(on);

}

}

 

Each time the button is clicked, method actionPerformed(ActionEvent) is called. The boolean (true or false) variable called 'on' is toggled to the opposite of its current state ('!' is the Java 'not' operator). We then call method setOn(boolean) in class LightBox2 (a slightly enhanced version of class LightBox).

Class LightBox2 extends class LightBox and adds 'accessor' (get/is and set) methods for the color property (or 'attribute') - the field 'col' already defined in the parent class (or 'superclass') LightBox. Class LightBox2 also provides a new method - setOn(boolean) - for external objects to set its 'on' state.

The constructor of LightBox2 calls super() which means the equivalent method in the superclass (the no-parameters constructor in this case). We do this because the constructor code is the same as in class LightBox. We could add some additional statements in our new constructor, but the call to super() must be the first line (if it is included).

Notice that we do not need to specify the fields 'on' and 'col' in this child class beacuse they are already specified in the parent class. Similarly, we do not need to put in code for methods paint(Graphics) or Dimension getPreferredSize() because we inherit these from the parent class. However, we could reimplement ('overide') them here if we wished to change the way that they worked.

Here is the source code for class LightBox2:

package projects.guicomps;

import java.awt.*;

import javax.swing.*;

public class LightBox2 extends LightBox {

// Constructor

public LightBox2() {

super();

}

 

public void setOn(boolean b) {

on=b;

repaint();

}

 

public boolean isOn() {

return on;

}

 

public void setColor(Color c) {

col=c;

}

}

 

Another way to achieve our goal of having a light controlled by a single button would be by having a toggling light! This is what we will do for Example5.

The first step is to create our toggling light class. We will call this class ToggleLightBox and base it on class LightBox2. This time the ActionListener will be the toggling light class, with the toggling action in the actionPerformed() method as before.

Here is the source code for class ToggleLightBox:

package projects.guicomps;

import java.awt.*;

import java.awt.event.*;

public class ToggleLightBox extends LightBox2 implements ActionListener {

// Constructor

public ToggleLightBox() {

setOn(false);

}

 

// A second constructor

public ToggleLightBox(Color c) {

setOn(false);

setColor(c);

}

 

public void actionPerformed(ActionEvent e) {

setOn(!isOn());

}

}

 

Notice that there are two constructors in this class. The name is the same in each case but the parameters are different. The first has no parameters, and the second has one - class Color. This technique can be applied to ordinary methods too and is called 'method overloading' (same method name, different parameter types or number of parameters).

In our case it provides a convenience. Without the second constructor, one might need to write the following code to get a cyan colored light object:

ToggleLightBox light=new ToggleLightBox();

light.setColor(Color.cyan);

but by using the second constructor we can simply write:

ToggleLightBox light=new ToggleLightBox(Color.cyan);

Here is the source code for class Example5:

package projects.tjioo5;

import projects.guicomps.*;

import java.awt.*;

import javax.swing.*;

public class Example5 extends JPanel {

// Constructor

public Example5() {

ToggleLightBox light=new ToggleLightBox();

 

JButton button=new JButton("Light");

button.addActionListener(light);

 

add(button);

add(light);

 

// let's add a second pair of buttons and lights

add(new JLabel(" "));

ToggleLightBox light2=new ToggleLightBox(Color.yellow);

JButton button2=new JButton("Light");

button2.addActionListener(light2);

add(button2);

add(light2);

 

// and a third pair

add(new JLabel(" "));

ToggleLightBox light3=new ToggleLightBox(Color.cyan);

JButton button3=new JButton("Light");

button3.addActionListener(light3);

add(button3);

add(light3);

}

}

 

This example demonstrates a fundamental aspect of object-oriented programming - that you can create any number of objects from a class.

There is another important lesson to learn here. Notice that the constructor is both long and repetitive. This is a sign that we should consider creating a submethod. By using a submethod (called addButtonLightPair(Color)), the code becomes much shorter - and also more likely to be free of errors and easier to maintain. Here is our revised class:

package projects.tjioo5;

import projects.guicomps.*;

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class Example5 extends JPanel {

// Constructor

public Example5() {

addButtonLightPair(Color.red);

 

// let's add a second pair of buttons and lights

add(new JLabel(" ")); // a space

addButtonLightPair(Color.yellow);

 

// add a third pair

add(new JLabel(" "));

addButtonLightPair(Color.cyan);

}

 

private void addButtonLightPair(Color col) {

ToggleLightBox light=new ToggleLightBox(col);

JButton button=new JButton("Light");

button.addActionListener(light);

add(button);

add(light);

}

}

 

In a case like this, creating a private (not called from outside the class) submethod is an excellent solution. Whenever you find that you have code that performs basically the same functionality in a number of places, perhaps in different methods (or even different classes), consider creating a new method and calling it as required. If the new method is general in nature and could be useful again, put it in a different package so that it can be used by many projects.

In the last section we develop a useful, reusable GUI component.

 

Download and run ...

You can download the source code for the example programs as a TJI project from the 'Resources' page of our website.

(c) Kinabaloo Software

Return to index