super.setVisiblevisible is called so that the corresponding method in the Frame class can take care of actually making the GUIFramevisible.. Here is a test of the GUIFrameclass, GUIFrame
Trang 1First off, it extends Frame, so it is a Frame It sets its background color to System-Color.control, which as you might remember from the previous chapter, is the color that your operating system uses for painting windows Then it adds a Win-dowAdapterobject as its WindowListener Pay close attention to the syntax here This is actually an inner-class declaration, which you’ll learn about later on in this chapter
Another cool thing it does is center itself, no matter what size it is when it becomes visible I did this by overriding the setVisible(boolean)method If the argument passed in is true, I get the screen size by calling Toolkit.getDefault-Toolkit().getScreenSize(), which returns a Dimensionobject representing the resolution of the computer screen, whether it is 640 by 480, 800 by 600, or what-ever The Toolkitclass is the abstract subclass of all implementations of the AWT, the default of which is different depending on what operating system you are running To center the GUIFrameon screen I needed to know the screen size and the size of the GUIFrame The position of the GUIFrameis set with the setLoca-tion(int, int)method, where the first intis the xlocation and the second int
is the ylocation The center location is half the difference of the screen width minus the GUIFramewidth as the xposition, and half the difference of the screen height minus the GUIFrameheight as the yposition super.setVisible(visible)
is called so that the corresponding method in the Frame class can take care of actually making the GUIFramevisible Take a look at Figure 7.7 to see what the
GUIFramelooks like Here is a test of the GUIFrameclass, GUIFrameTest: /*
* GUIFrameTest
* Demonstrates the GUIFrame Class
*/
public class GUIFrameTest { public static void main(String args[]) { GUIFrame frame = new GUIFrame("GUIFrame Test");
frame.setSize(400, 300);
frame.setVisible(true);
} }
Using CardLayout
The CardLayoutlayout manager lays out its components as cards You can think
of each card as a card within a deck of playing cards To make this analogy work, imagine that the cards are face up and only the top card is visible You can take
a card off the top of the deck and add it to the bottom to make the next card vis-ible Each card is actually a Java component Only one of the components is
visi-238
J a
s o
l ut
n e
Trang 2ble at a time The first component added to the layout is visible when the con-tainer is initially visible CardLayouthas some methods that change which com-ponent is visible, as you can see in Table 7.5 When adding comcom-ponents to a
CardLayout, you specify a string That string is used as an identifier so that you can flip directly to that card when necessary The name of the class is pretty self-explanatory You can think of it as a deck of cards or a deck of components that
239
FIGURE 7.7
The GUIFrame class tested here is used throughout this chapter.
Method Description
CardLayout() Constructs a CardLayout object with no horizontal or
vertical gaps.
CardLayout(int, int) Constructs a CardLayout object with the given
horizontal and vertical gaps.
void first(Container) Displays the first card of the given Containerobject.
void last(Container) Displays the last card of the given Containerobject.
void next(Container) Displays the next card of the given Containerobject.
void previous(Container) Displays the previous card of the given Container
object.
void show(String, Container) Displays the card that was added to this Container
using the specified Stringidentifier.
T A B L E 7 5 C A R D L A Y O U T M E T H O D S
Trang 3can be traversed through, or dealt, one at a time The CardLayoutTestapplication
is an example:
/*
* CardLayoutTest
* Demonstrates the CardLayout layout manager
*/
import java.awt.*;
import java.awt.event.*;
public class CardLayoutTest extends GUIFrame
implements ActionListener { Panel cardPanel;
Panel buttonPanel;
Button nextButton;
Button prevButton;
Label l1, l2, l3;
TextArea ta;
CardLayout cardLayout;
public CardLayoutTest() { super("CardLayout Test");
cardLayout = new CardLayout();
cardPanel = new Panel();
cardPanel.setLayout(cardLayout);
cardPanel.setBackground(Color.black);
cardPanel.setForeground(Color.yellow);
Font lFont = new Font("Verdana", Font.BOLD, 20);
l1 = new Label("First", Label.LEFT);
l1.setFont(lFont);
l2 = new Label("Second", Label.CENTER);
l2.setFont(lFont);
ta = new TextArea("You can put any Components"
+ "\nthat you want, or even add a Container"
+ "\nthat itself contains multiple Components", 4, 35);
ta.setForeground(Color.black);
l3 = new Label("Last", Label.RIGHT);
l3.setFont(lFont);
cardPanel.add("C1", l1);
cardPanel.add("C2", l2);
cardPanel.add("C3", ta);
cardPanel.add("C4", l3);
add(cardPanel, BorderLayout.CENTER);
buttonPanel = new Panel();
prevButton = new Button("Previous");
prevButton.addActionListener(this);
buttonPanel.add(prevButton);
nextButton = new Button("Next");
nextButton.addActionListener(this);
buttonPanel.add(nextButton);
add(buttonPanel, BorderLayout.SOUTH);
240
J a
s o
l ut
n e
Trang 4//pack sets the minimum size able to display the largest //Dimension Components
pack();
setVisible(true);
} public static void main(String args[]) { CardLayoutTest clt = new CardLayoutTest();
} public void actionPerformed(ActionEvent e) {
if (e.getSource() == nextButton) cardLayout.next(cardPanel);
else cardLayout.previous(cardPanel);
} }
CardLayoutTest extends GUIFrame, which itself has a BorderLayoutby default, but contains a Panel, cardPanel, which has its layout set to cardLayout, a Card-Layoutobject cardLayoutlays out three labels: l1, l2, and l3, and a TextArea, ta, inside of cardPanel The order that these are added is as follows:
cardPanel.add("C1", l1);
cardPanel.add("C2", l2);
cardPanel.add("C3", ta);
cardPanel.add("C4", l3);
Remember that the components are added along with a Stringidentifier, which can call up any one of the cards to the front After these four components are added to cardPanel, cardPanelis added to the GUIFrameat BorderLayout.CENTER
prevButton and nextButton are Button objects that I added to another Panel,
buttonPanel, which in turn, I added to the GUIFrame at BorderLayout.SOUTH Some event handling is required with these Buttons, covered in the next section
Basically prevButton causes cardLayout.previous(cardPanel) to be called and
nextButton causes cardLayout.next(cardPanel) to be called when they are clicked The output is shown in Figure 7.8
241
FIGURE 7.8
The CardLayout manager displays its components one
at a time.
Trang 5Handling AWT Events
Up to this point, you’ve learned how to create components and lay them out within a container However, you haven’t had much use for these components yet You were exposed to a bit of event handling already This section concen-trates on the java.awt.event package, which has classes that are used for handling events caused by user interaction with the AWT GUI interfaces you cre-ate In this section, you’ll learn about WindowEvents, ActionEvents, FocusEvents,
ItemEvents, AdjustmentEvents, TextEvents, MouseEvents, and KeyEvents The classes that you need to use to handle AWT events are in the java.awt.event
package, so don’t forget to import it into your applications All the Eventclasses explored here directly extend the abstract AWTEventclass or the ComponentEvent
class, which itself is a direct subclass of AWTEvent AWTEventis a subclass of the
EventObjectclass KeyEventand MouseEventextend InputEvent, which is a sub-class of ComponentEvent
You handle AWT events in Java (1.1 and higher) by implementing a listener
inter-face that “listens” for events that can be triggered by components A component
that triggers events must register the listeners so that the listeners can “hear” the
component’s events A component keeps a list of listeners that it informs when it triggers an event by calling one of its required methods For example, you already know that to be a WindowListener, a class must implement all six of the Win-dowListenerinterfaces When a WindowEventoccurs, the window will inform its listeners by calling one of those six methods, depending on which event has occurred This will become more intuitive to you the more you do it, and because
no GUI is useful without event handling, you will be using it every time you cre-ate one
Handling WindowEvents
You’ve already implemented the WindowListenerinterface in the previous chap-ter and also in this chapchap-ter Now you will learn about handling WindowEvents in more detail To handle WindowEvents, you need to implement the WindowListener
interface When you implement the WindowListener interface or any other abstract interface, you need to implement its methods, which are listed in Table 7.6 These methods are called when corresponding actions have taken place For
WindowListeners, when a window is opened, closed, activated, deactivated, iconi-fied (minimized), or deiconiiconi-fied (restored), the corresponding method is called to notify the interested “listener” class that the action has taken place
The WindowEventTest application is a test of the WindowListener interface It extends GUIFrame and implements WindowListener The window opens and the events are handled simply by printing to standard output the event that has
242
J a
s o
l ut
n e
Trang 6taken place, so as you perform actions on the window that pops up, pay attention
to the standard output so you can know when each method is called Here is the source code for WindowEventTest.java:
/*
* WindowEventTest
* Tests WindowEvents
*/
import java.awt.*;
import java.awt.event.*;
public class WindowEventTest implements WindowListener { public WindowEventTest() {
Frame frame = new Frame("WindowEvent Test");
frame.add(new Label("See Command Prompt output for event log "));
frame.addWindowListener(this);
frame.pack();
frame.setVisible(true);
} public static void main(String args[]) { WindowEventTest wet = new WindowEventTest();
} //WindowListener Interface public void windowClosing(WindowEvent e) {
Method Description
void windowActivated(WindowEvent) Called when a window becomes active (able to
accept input events).
void windowClosed(WindowEvent) Called when a window is closed (disposed).
void windowClosing(WindowEvent) Called when a user attempts to close a window.
You implement this method to conditionally close the window.
void windowDeactivated(WindowEvent) Called when a window is deactivated (loses
input focus).
void windowDeiconified(WindowEvent) Called when a window is restored from a
minimized state.
void windowIconified(WindowEvent) Called when a window becomes minimized.
void windowOpened(WindowEvent) Called when a window initially becomes visible.
T A B L E 7 6 W I N D O W L I S T E N E R M E T H O D S
Trang 7((Window)e.getSource()).dispose();
} public void windowOpened(WindowEvent e) { System.out.println("windowOpened");
} public void windowActivated(WindowEvent e) { System.out.println("windowActivated");
} public void windowDeactivated(WindowEvent e) { System.out.println("windowDeactivated");
} public void windowIconified(WindowEvent e) { System.out.println("windowIconified");
} public void windowDeiconified(WindowEvent e) { System.out.println("windowDeiconified");
} public void windowClosed(WindowEvent e) { System.out.println("windowClosed");
System.exit(0);
} } Most of the code here should be familiar You’ve already used the methods of the
WindowListenerinterface before, except that before now, you implemented them except for windowClosing(WindowEvent) as empty do-nothing methods Previ-ously, you had always called System.exit(0)in the windowClosing(WindowEvent)
method In this program, you wanted to see the windowClosed(WindowEvent)
method triggered, so instead, you called:
((Window)e.getSource()).dispose();
As you learned in the previous chapter, the dispose()method releases all native resources used for the window and its subcomponents and closes the window You can make the window displayable again, though, assuming System.exit(0)
isn’t called (which it is here) by calling pack() or show() The getSource()
method of the WindowEventclass, inherited from EventObject, is discussed in the next section Basically, e.getSource()returns the object that initiated this Win-dowEvent, which in this case will always be the WindowEventTest object In the
windowClosed(WindowEvent)method, I called System.exit(0)to exit the Java VM after the window is closed The windowClosed(WindowEvent)method is triggered when the dispose()method is called, closing the window
The WindowEventTest class implements the WindowListener interface, so it becomes WindowListeneritself, which is better than a window watcher, like the lady that lives across the street from me and calls the police if I forget about a
244
J a
s o
l ut
n e
Trang 8holiday and bring my garbage out on the wrong day Anyway, WindowEventTestis also a Framebecause it extends Frame It is the Frameand the WindowListenerthat listens to itself It registers itself as a listener by calling the addWindowLis-tener(WindowListener)method and passing itself as an argument by using the
thiskeyword Because of this, when a WindowEventis triggered, it will call one of its own WindowListenermethods so that it can handle its own events This is not the only way to do it, though It can register any WindowListener, or even multi-ple listeners, also by calling the addWindowListener(WindowListener)method for each of them
You can see the output of this application in Figure 7.9 When I started the appli-cation, using the command:
java WindowEventTest
245
FIGURE 7.9
The WindowEventTest application shows how to capture WindowEvents
It ran the first two lines of output, windowActivated and windowOpened After that, I minimized the window, running the next two lines, windowIconifiedand windowDeactivated Then I restored the window (using Windows by clicking the icon on the taskbar), which triggered three events These events—windowActi-vated, windowDeiconified, and windowActivated—generated the output, indicat-ing that I activated the window by initially interactindicat-ing with it on the taskbar As the window was restored, the window triggered the windowDeiconified(Window-Event)method; finally, the window was activated again
When I closed the window by clicking the close button (the x), the windowClos-ingand windowClosedlines printed in the output
Trang 9Using Inner Adapter Classes
You’re probably thinking, yeah, okay, Joe, what about that funky code in
GUIFrame.java that closes the window? It doesn’t implement WindowListener, nor does it define its methods, like you just told me I have to do, right? Well, actu-ally it does, indirectly
The WindowAdapterclass implements the WindowListenerinterface and defines the methods as empty do-nothing methods The sole purpose of the Win-dowAdapter class and other adapter classes, such as FocusAdapter, KeyAdapter,
MouseAdapter, and MouseMotionAdapter, is to facilitate the implementation of their respective listener interfaces Because they are classes that implement the listener’s methods as do-nothing methods, you don’t have to implement them all You only need to implement the ones that you are interested in In the
GUIFrameclass, you add the WindowListeneras follows:
addWindowListener(new WindowAdapter() { //only need to override the method needed public void windowClosing(WindowEvent e) { dispose();
System.exit(0);
} });
The code is even more confusing because the windowClosing(WindowEvent)
method is overridden right within the call to the addWindowListener(WindowLis-tener)method The declaration of the WindowAdapterhere is called an anonymous inner class Here, I am creating a subclass of WindowAdapterand overriding its win-dowClosing(WindowEvent)method without actually giving that subclass a name and I am doing this within another class’s definition That’s why it’s called an anonymous inner class Take a look at the files in the directory where you com-piled GUIFrame.java You will see a file named GUIFrame$1.class This file holds
246
J a
s o
l ut
n e
I N THE R EAL W ORLD
In the real world, the windowClosing(WindowEvent) method tells you when a user attempts to exit your GUI program As you saw in Chapter 6, you don’t have to close the window when a user wants to close it (remember UselessFrame ?) This allows programmers to catch the window-closing event, so they can perform whatever cleanup is necessary It also is a safeguard against bad data A pro-grammer can store the changes made to the data while the window was opened before actually exiting the system, or perhaps, prompt the user: “Are you sure you want me to go away, sniff?” It’s good to know when a user wants
to exit the program for reasons such as these.
Trang 10the class definition of the anonymous WindowAdaptersubclass The syntax for cre-ating an anonymous inner class is as follows:
OuterClass { new InnerClassName(constructor_arguments) { subclass_definition;
} } Inner classes are Java classes that are defined within the curly braces of another class An inner class has access to the outer classes’ members and methods For now, this is all you need to know about inner classes You will revisit this topic in Chapter 11, “Custom Event Handling and File I/O.”
Handling ActionEvents
ActionEvents are high-level events that are triggered by a component when it generates an event, such as a clicked Button ActionEvents are listened to by implementing the ActionListener interface This interface defines only one method actionPerformed(ActionEvent) Take a look at ButtonEventTest.java, which implements the ActionListenerinterface:
/*
* ButtonEventTest
* Demonstrates using ActionListener to handle Button
* events by counting the number of times a button is clicked.
*/
import java.awt.*;
import java.awt.event.*;
public class ButtonEventTest extends GUIFrame
implements ActionListener { Button button;
int count;
Label clicksLabel;
public ButtonEventTest() { super("Button Event Test");
button = new Button("Button");
button.addActionListener(this);
add(button, BorderLayout.CENTER);
count = 0;
clicksLabel = new Label();
updateLabel();
add(clicksLabel, BorderLayout.SOUTH);
setSize(200, 200);
setVisible(true);
}
247