The Button class creates pushbuttons with text labels. Java doesn't have a built-in class that supports buttons with images, but in Section 13.3 we'll build one by extending the Canvas class. The most common usage is to simply create one with a specified label, drop it in a window, then watch for action events to see if it has been pressed. For instance, to create a button and add it to the current window, you'd do something like the following:
Button button = new Button("...");
add(button);
This creates a button with the specified label. Its preferredSize (used by layout managers like FlowLayout and BorderLayout) is based on the height and width of the label in the current font, plus some extra space that varies depending on the window system being used.
This creates a button with no label. One can be added later via set-Label. The width reported by preferredSize is greater than zero even when there is no label, because the border requires some space.
Listing 13.7 shows an applet that contains three buttons. In this particular case, because we don't ever do anything with the buttons, there is no need to assign the Button objects to separate instance variables. It is sufficient to simply do add(new Button(...)). However, you will want access to the buttons when you go to give them behavior, so you might as well plan ahead and store the button references somewhere that will be accessible in other methods.
One of the key features of user interface controls in Java is that they take on the look and feel of the operating system they are running on. Figures 13-4, 13-5, and 13-6 show the results of Listing 13.7 in Netscape 3 on Windows 95, MacOS, and Solaris, respectively.
Listing 13.7
|
|---|
import java.applet.Applet;
import java.awt.*;
public class Buttons extends Applet {
private Button button1, button2, button3;
public void init() {
button1 = new Button("Button One");
button2 = new Button("Button Two");
button3 = new Button("Button Three");
add(button1);
add(button2);
add(button3);
}
}
|
The getLabel method retrieves the current label.
The setLabel method changes the button's label. If the button is already displayed, doing this does not automatically resize it in its Container. So the containing window should be invalidated and validated to force a fresh layout, as below:
someButton.setLabel("A New Label");
someButton.getParent().invalidate();
someButton.getParent().validate();
These methods add and remove objects that process action events. See the following subsection for a discussion of their use.
These Java 1.1 methods are used to associate a string with the button. The idea is that this string stays the same even when the label changes in internationalized code. The string can be retrieved in event-processing code by calling the getActionCommand method of ActionEvent. The default string is simply the label of the button.
This is a low-level event-processing routine used when you want a button to handle its own events. If you use it, don't forget to enable events first with enableEvents, and to call super.processActionEvent from within the body of the method. See the following section for examples.
Also, as with every Component (Section 11.2), buttons have getForeground, setForeground, getBackground, setBackground, getFont, setFont, and a variety of other inherited methods. However, setForeground and setBackground are ignored on many Windows and MacOS implementations. In particular, Netscape version 2 and 3, Internet Explorer version 3, and Sun JDK 1.02 all ignore button foreground and background colors on Windows 95 and NT. JDK 1.1.3 and Netscape 4.01 honor them on Windows 95/NT. They work on virtually all Unix implementations.
Most 1.02 Java implementations and browsers ignore button foreground and background colors on Windows 95/NT and MacOS.
Precisely how Java determines that a button has been activated depends on the operating system. However, typically activation is either when the user clicks and releases the mouse on a button or when the user enters a carriage return while the button has the input focus.
In Java 1.0, events can be handled in the action method of the button itself by making a Button subclass. If not, the event gets passed to the Container, which can handle it there. But because the Container may contain more than one Component, if the event is handled there it first needs to determine which component was activated before acting upon it, as in the following example:
public boolean action(Event event, Object object) {
if (event.target == button1) {
doActionForButton1();
return(true);
} else ...
}
When action is called for a button, Java passes the button's label as the second argument. It has become common practice to determine which Button was activated by comparing the label to this argument (i.e. by checking if object.equals("Button Label")), rather than comparing event.target to the instance variable storing the Button. Although this can be a tiny bit shorter since you don't have to have a Button instance variable, I recommend against using this approach in production code for the following reasons:
init or constructor and action), and the second change can easily be overlooked. <FACETIOUS>Normally, you might argue that comparing to the label is good for job security for this very reason (nobody except you will be able to maintain the code). Fortunately, the demand for Java programmers is so high right now that we can dispense with this argument.</FACETIOUS>String comparison is more expensive.
When handling action events in the enclosing window's action method, determine which button was selected by checking the button object reference, not by comparing to the button's label.
Like other action events, you can handle button events one of two ways. To handle events in the Button object itself, first enable action events via
enableEvents(AWTEvent.ACTION_EVENT_MASK);
Next, override processActionEvent to perform the specific behavior you want. You should call super.processActionEvent in the body so that, if anyone else attaches listeners to your button, they will still be invoked. Following is an abstract example; for specifics see SetSizeButton (Listing 13.5):
public void processActionEvent(ActionEvent event) {
takeSomeAction(...);
super.processActionEvent(event); // Handle listeners
}
That's the first possible approach: processing events in the Button itself. The next option is to attach one or more ActionListeners to the button. To do that, create an object that implements the ActionListener interface, put the action to be taken in the actionPerformed method, then associate it with the button via addActionListener. In Listing 13.6, the window itself was the ActionListener, but you can do this a variety of ways. For instance, Listing 13.8 creates three buttons, each with one to three different ActionListeners attached. It associates an FgReporter (Listing 13.9) with the first button, an FgReporter and a BgReporter (Listing 13.10) with the second, and an FgReporter, a BgReporter, and a SizeReporter (Listing 13.11) with the third. Each of these reporters is an ActionListener that simply prints some information about the component that was the source of the action. Figure 13-7 shows the result, with the output after clicking on the three buttons once each shown in Listing 13.12.
Listing 13.8
|
|---|
import java.awt.*;
import java.awt.event.*;
// JDK 1.1 Only
public class ButtonExample extends CloseableFrame {
public static void main(String[] args) {
new ButtonExample();
}
public ButtonExample() {
super("Using ActionListeners in JDK 1.1");
setLayout(new FlowLayout());
Button b1 = new Button("Button 1");
Button b2 = new Button("Button 2");
Button b3 = new Button("Button 3");
b1.setBackground(Color.lightGray);
b2.setBackground(Color.gray);
b3.setBackground(Color.darkGray);
FgReporter fgReporter = new FgReporter();
BgReporter bgReporter = new BgReporter();
SizeReporter sizeReporter = new SizeReporter();
b1.addActionListener(fgReporter);
b2.addActionListener(fgReporter);
b2.addActionListener(bgReporter);
b3.addActionListener(fgReporter);
b3.addActionListener(bgReporter);
b3.addActionListener(sizeReporter);
add(b1);
add(b2);
add(b3);
setSize(350, 100);
setVisible(true);
}
}
|
Listing 13.9
|
|---|
import java.awt.event.*;
import java.awt.*;
// JDK 1.1 Only
public class FgReporter implements ActionListener {
public void actionPerformed(ActionEvent event) {
Component c = (Component)event.getSource();
System.out.println("Foreground: " +
c.getForeground());
}
}
|
Listing 13.10
|
|---|
import java.awt.event.*;
import java.awt.*;
// JDK 1.1 Only
public class BgReporter implements ActionListener {
public void actionPerformed(ActionEvent event) {
Component c = (Component)event.getSource();
System.out.println("Background: " +
c.getBackground());
}
}
|
Listing 13.11
|
|---|
import java.awt.event.*;
import java.awt.*;
// JDK 1.1 Only
public class SizeReporter implements ActionListener {
public void actionPerformed(ActionEvent event) {
Component c = (Component)event.getSource();
Dimension d = c.getSize();
System.out.println("Size: " + d.width + "x" +
d.height);
}
}
|
ActionListener to a 1.1
component.
Listing 13.12 ButtonExample output after pressing Button 1, Button 2, and Button 3 once each in that order. |
|---|
Foreground: java.awt.Color[r=0,g=0,b=0] Foreground: java.awt.Color[r=0,g=0,b=0] Background: java.awt.Color[r=128,g=128,b=128] Foreground: java.awt.Color[r=0,g=0,b=0] Background: java.awt.Color[r=64,g=64,b=64] Size: 59x23 |
| Continue to Section 13.3 (An Image Button Class). | Return to Chapter 13 table of contents. |
|---|