- •CONTENTS
- •1.1 Introduction
- •1.2 What Is a Computer?
- •1.3 Programs
- •1.4 Operating Systems
- •1.5 Java, World Wide Web, and Beyond
- •1.6 The Java Language Specification, API, JDK, and IDE
- •1.7 A Simple Java Program
- •1.8 Creating, Compiling, and Executing a Java Program
- •1.9 (GUI) Displaying Text in a Message Dialog Box
- •2.1 Introduction
- •2.2 Writing Simple Programs
- •2.3 Reading Input from the Console
- •2.4 Identifiers
- •2.5 Variables
- •2.7 Named Constants
- •2.8 Numeric Data Types and Operations
- •2.9 Problem: Displaying the Current Time
- •2.10 Shorthand Operators
- •2.11 Numeric Type Conversions
- •2.12 Problem: Computing Loan Payments
- •2.13 Character Data Type and Operations
- •2.14 Problem: Counting Monetary Units
- •2.15 The String Type
- •2.16 Programming Style and Documentation
- •2.17 Programming Errors
- •2.18 (GUI) Getting Input from Input Dialogs
- •3.1 Introduction
- •3.2 boolean Data Type
- •3.3 Problem: A Simple Math Learning Tool
- •3.4 if Statements
- •3.5 Problem: Guessing Birthdays
- •3.6 Two-Way if Statements
- •3.7 Nested if Statements
- •3.8 Common Errors in Selection Statements
- •3.9 Problem: An Improved Math Learning Tool
- •3.10 Problem: Computing Body Mass Index
- •3.11 Problem: Computing Taxes
- •3.12 Logical Operators
- •3.13 Problem: Determining Leap Year
- •3.14 Problem: Lottery
- •3.15 switch Statements
- •3.16 Conditional Expressions
- •3.17 Formatting Console Output
- •3.18 Operator Precedence and Associativity
- •3.19 (GUI) Confirmation Dialogs
- •4.1 Introduction
- •4.2 The while Loop
- •4.3 The do-while Loop
- •4.4 The for Loop
- •4.5 Which Loop to Use?
- •4.6 Nested Loops
- •4.7 Minimizing Numeric Errors
- •4.8 Case Studies
- •4.9 Keywords break and continue
- •4.10 (GUI) Controlling a Loop with a Confirmation Dialog
- •5.1 Introduction
- •5.2 Defining a Method
- •5.3 Calling a Method
- •5.4 void Method Example
- •5.5 Passing Parameters by Values
- •5.6 Modularizing Code
- •5.7 Problem: Converting Decimals to Hexadecimals
- •5.8 Overloading Methods
- •5.9 The Scope of Variables
- •5.10 The Math Class
- •5.11 Case Study: Generating Random Characters
- •5.12 Method Abstraction and Stepwise Refinement
- •6.1 Introduction
- •6.2 Array Basics
- •6.3 Problem: Lotto Numbers
- •6.4 Problem: Deck of Cards
- •6.5 Copying Arrays
- •6.6 Passing Arrays to Methods
- •6.7 Returning an Array from a Method
- •6.8 Variable-Length Argument Lists
- •6.9 Searching Arrays
- •6.10 Sorting Arrays
- •6.11 The Arrays Class
- •7.1 Introduction
- •7.2 Two-Dimensional Array Basics
- •7.3 Processing Two-Dimensional Arrays
- •7.4 Passing Two-Dimensional Arrays to Methods
- •7.5 Problem: Grading a Multiple-Choice Test
- •7.6 Problem: Finding a Closest Pair
- •7.7 Problem: Sudoku
- •7.8 Multidimensional Arrays
- •8.1 Introduction
- •8.2 Defining Classes for Objects
- •8.3 Example: Defining Classes and Creating Objects
- •8.4 Constructing Objects Using Constructors
- •8.5 Accessing Objects via Reference Variables
- •8.6 Using Classes from the Java Library
- •8.7 Static Variables, Constants, and Methods
- •8.8 Visibility Modifiers
- •8.9 Data Field Encapsulation
- •8.10 Passing Objects to Methods
- •8.11 Array of Objects
- •9.1 Introduction
- •9.2 The String Class
- •9.3 The Character Class
- •9.4 The StringBuilder/StringBuffer Class
- •9.5 Command-Line Arguments
- •9.6 The File Class
- •9.7 File Input and Output
- •9.8 (GUI) File Dialogs
- •10.1 Introduction
- •10.2 Immutable Objects and Classes
- •10.3 The Scope of Variables
- •10.4 The this Reference
- •10.5 Class Abstraction and Encapsulation
- •10.6 Object-Oriented Thinking
- •10.7 Object Composition
- •10.8 Designing the Course Class
- •10.9 Designing a Class for Stacks
- •10.10 Designing the GuessDate Class
- •10.11 Class Design Guidelines
- •11.1 Introduction
- •11.2 Superclasses and Subclasses
- •11.3 Using the super Keyword
- •11.4 Overriding Methods
- •11.5 Overriding vs. Overloading
- •11.6 The Object Class and Its toString() Method
- •11.7 Polymorphism
- •11.8 Dynamic Binding
- •11.9 Casting Objects and the instanceof Operator
- •11.11 The ArrayList Class
- •11.12 A Custom Stack Class
- •11.13 The protected Data and Methods
- •11.14 Preventing Extending and Overriding
- •12.1 Introduction
- •12.2 Swing vs. AWT
- •12.3 The Java GUI API
- •12.4 Frames
- •12.5 Layout Managers
- •12.6 Using Panels as Subcontainers
- •12.7 The Color Class
- •12.8 The Font Class
- •12.9 Common Features of Swing GUI Components
- •12.10 Image Icons
- •13.1 Introduction
- •13.2 Exception-Handling Overview
- •13.3 Exception-Handling Advantages
- •13.4 Exception Types
- •13.5 More on Exception Handling
- •13.6 The finally Clause
- •13.7 When to Use Exceptions
- •13.8 Rethrowing Exceptions
- •13.9 Chained Exceptions
- •13.10 Creating Custom Exception Classes
- •14.1 Introduction
- •14.2 Abstract Classes
- •14.3 Example: Calendar and GregorianCalendar
- •14.4 Interfaces
- •14.5 Example: The Comparable Interface
- •14.6 Example: The ActionListener Interface
- •14.7 Example: The Cloneable Interface
- •14.8 Interfaces vs. Abstract Classes
- •14.9 Processing Primitive Data Type Values as Objects
- •14.10 Sorting an Array of Objects
- •14.11 Automatic Conversion between Primitive Types and Wrapper Class Types
- •14.12 The BigInteger and BigDecimal Classes
- •14.13 Case Study: The Rational Class
- •15.1 Introduction
- •15.2 Graphical Coordinate Systems
- •15.3 The Graphics Class
- •15.4 Drawing Strings, Lines, Rectangles, and Ovals
- •15.5 Case Study: The FigurePanel Class
- •15.6 Drawing Arcs
- •15.7 Drawing Polygons and Polylines
- •15.8 Centering a String Using the FontMetrics Class
- •15.9 Case Study: The MessagePanel Class
- •15.10 Case Study: The StillClock Class
- •15.11 Displaying Images
- •15.12 Case Study: The ImageViewer Class
- •16.1 Introduction
- •16.2 Event and Event Source
- •16.3 Listeners, Registrations, and Handling Events
- •16.4 Inner Classes
- •16.5 Anonymous Class Listeners
- •16.6 Alternative Ways of Defining Listener Classes
- •16.7 Problem: Loan Calculator
- •16.8 Window Events
- •16.9 Listener Interface Adapters
- •16.10 Mouse Events
- •16.11 Key Events
- •16.12 Animation Using the Timer Class
- •17.1 Introduction
- •17.2 Buttons
- •17.3 Check Boxes
- •17.4 Radio Buttons
- •17.5 Labels
- •17.6 Text Fields
- •17.7 Text Areas
- •17.8 Combo Boxes
- •17.9 Lists
- •17.10 Scroll Bars
- •17.11 Sliders
- •17.12 Creating Multiple Windows
- •18.1 Introduction
- •18.2 Developing Applets
- •18.3 The HTML File and the <applet> Tag
- •18.4 Applet Security Restrictions
- •18.5 Enabling Applets to Run as Applications
- •18.6 Applet Life-Cycle Methods
- •18.7 Passing Strings to Applets
- •18.8 Case Study: Bouncing Ball
- •18.9 Case Study: TicTacToe
- •18.10 Locating Resources Using the URL Class
- •18.11 Playing Audio in Any Java Program
- •18.12 Case Study: Multimedia Animations
- •19.1 Introduction
- •19.2 How is I/O Handled in Java?
- •19.3 Text I/O vs. Binary I/O
- •19.4 Binary I/O Classes
- •19.5 Problem: Copying Files
- •19.6 Object I/O
- •19.7 Random-Access Files
- •20.1 Introduction
- •20.2 Problem: Computing Factorials
- •20.3 Problem: Computing Fibonacci Numbers
- •20.4 Problem Solving Using Recursion
- •20.5 Recursive Helper Methods
- •20.6 Problem: Finding the Directory Size
- •20.7 Problem: Towers of Hanoi
- •20.8 Problem: Fractals
- •20.9 Problem: Eight Queens
- •20.10 Recursion vs. Iteration
- •20.11 Tail Recursion
- •APPENDIXES
- •INDEX
534 Chapter 16 Event-Driven Programming
|
16.1 Introduction |
problem |
Suppose you wish to write a GUI program that lets the user enter the loan amount, annual inter- |
|
est rate, and number of years and click the Compute Loan button to obtain the monthly payment |
|
and total payment, as shown in Figure 16.1(a). How do you accomplish the task? You have to |
|
use event-driven programming to write the code to respond to the button-clicking event. |
(a) |
(b) |
(c) |
(d) |
FIGURE 16.1 (a) The program computes loan payments. (b)–(d) A flag is rising upward.
Suppose you wish to write a program that animates a rising flag, as shown in Figure problem 16.1(b)–(d). How do you accomplish the task? There are several ways to solve this problem.
An effective one is to use a timer in event-driven programming, which is the subject of this chapter.
In event-driven programming, code is executed when an event occurs (e.g., a button click, a mouse movement, or a timer). §14.6, “Example: The ActionListener Interface,” gave you a taste of event-driven programming. You probably have many questions, such as why a listener class is defined to implement the ActionListener interface. This chapter will give you all the answers.
|
16.2 Event and Event Source |
|
When you run a Java GUI program, the program interacts with the user, and the events drive |
event |
its execution. An event can be defined as a signal to the program that something has hap- |
|
pened. Events are triggered either by external user actions, such as mouse movements, button |
|
clicks, and keystrokes, or by internal program activities, such as a timer. The program can |
|
choose to respond to or ignore an event. |
fire event |
The component that creates an event and fires it is called the source object or source compo- |
source object |
nent. For example, a button is the source object for a button-clicking action event. An event is an |
|
instance of an event class. The root class of the event classes is java.util.EventObject. |
|
The hierarchical relationships of some event classes are shown in Figure 16.2. |
|
ActionEvent |
ContainerEvent |
|
|
AdjustmentEvent |
FocusEvent |
MouseEvent |
AWTEvent |
ComponentEvent |
InputEvent |
|
|
ItemEvent |
PaintEvent |
KeyEvent |
|
TextEvent |
WindowEvent |
|
ListSelectionEvent
ChangeEvent
FIGURE 16.2 An event is an object of the EventObject class.
16.3 Listeners, Registrations, and Handling Events 535
An event object contains whatever properties are pertinent to the event. You can identify
the source object of an event using the getSource() instance method in the EventObject getSource() class. The subclasses of EventObject deal with special types of events, such as action
events, window events, component events, mouse events, and key events. Table 16.1 lists external user actions, source objects, and event types fired.
TABLE 16.1 User Action, Source Object, and Event Type
User Action |
Source Object |
Event Type Fired |
|
|
|
Click a button |
JButton |
ActionEvent |
Press return on a text field |
JTextField |
ActionEvent |
Select a new item |
JComboBox |
ItemEvent, ActionEvent |
Select item(s) |
JList |
ListSelectionEvent |
Click a check box |
JCheckBox |
ItemEvent, ActionEvent |
Click a radio button |
JRadioButton |
ItemEvent, ActionEvent |
Select a menu item |
JMenuItem |
ActionEvent |
Move the scroll bar |
JScrollBar |
AdjustmentEvent |
Move the scroll bar |
JSlider |
ChangeEvent |
Window opened, closed, iconified, |
Window |
WindowEvent |
deiconified, or closing |
|
|
Mouse pressed, released, clicked, |
Component |
MouseEvent |
entered, or exited |
|
|
Mouse moved or dragged |
Component |
MouseEvent |
Key released or pressed |
Component |
KeyEvent |
Component added or removed from |
Container |
ContainerEvent |
the container |
|
|
Component moved, resized, |
Component |
ComponentEvent |
hidden, or shown |
|
|
Component gained or lost focus |
Component |
FocusEvent |
Note
If a component can fire an event, any subclass of the component can fire the same type of event.
For example, every GUI component can fire MouseEvent, KeyEvent, FocusEvent, and
ComponentEvent, since Component is the superclass of all GUI components.
Note
All the event classes in Figure 16.2 are included in the java.awt.event package except
ListSelectionEvent and ChangeEvent, which are in the javax.swing.event package. AWT events were originally designed for AWT components, but many Swing components fire them.
16.3 Listeners, Registrations, and Handling Events
Java uses a delegation-based model for event handling: a source object fires an event, and |
|
an object interested in the event handles it. The latter object is called a listener. For an |
listener |
object to be a listener for an event on a source object, two things are needed, as shown in |
ActionEvent/ActionListener |
Figure 16.3. |
|
536 Chapter 16 Event-Driven Programming
User |
Trigger an event |
source: SourceClass |
|
||
Action |
|
+addXListener(listener: XListener) |
|
|
(2) Register by invoking source.addXListener(listener);
(1) A listener object is an instance of a listener interface
(a) A generic source component with a generic listener
«interface»
XListener
+handler(event: XEvent)
listener: ListenerClass
|
|
|
«interface» |
|
source: javax.swing.JButton |
|
|
java.awt.event.ActionListener |
|
+addActionListener(listener: ActionListener) |
|
+actionPerformed(event: ActionEvent) |
||
(2) Register by invoking |
|
|
|
|
source.addActionListener(listener); |
|
|
|
|
(1) An action event listener is an |
|
|||
listener: CustomListenerClass |
|
|||
instance of ActionListener |
|
|
(b) A JButton source component with an ActionListener
FIGURE 16.3 A listener must be an instance of a listener interface and must be registered with a source component.
|
|
1. The listener object must be an instance of the corresponding event-listener interface to |
|
|
|
ensure that the listener has the correct method for processing the event. Java provides a |
|
listener interface |
|
listener interface for every type of event. The listener interface is usually named |
|
XListener/XEvent |
|
XListener for XEvent, with the exception of MouseMotionListener. For example, the |
|
|
|
corresponding listener interface for ActionEvent is ActionListener; each listener for |
|
|
|
ActionEvent should implement the ActionListener interface. Table 16.2 lists event |
|
|
|
types, the corresponding listener interfaces, and the methods defined in the listener inter- |
|
handler |
|
faces. The listener interface contains the method(s), known as the handler(s), for processing |
|
|
|
the event. |
|
|
2. The listener object must be registered by the source object. Registration methods |
||
|
|
depend on the event type. For ActionEvent, the method is addActionListener. In |
|
|
|
general, the method is named addXListener for XEvent. A source object may fire |
|
register listener |
|
several types of events. It maintains, for each event, a list of registered listeners and |
|
|
|
notifies them by invoking the handler of the listener object to respond to the event, as |
|
|
|
shown in Figure 16.4. (Figure 16.4 shows the internal implementation of a source class. |
|
|
|
You don’t have to know how a source class such as JButton is implemented in order to |
|
|
|
use it. Nevertheless, this knowledge will help you to understand the Java event-driven |
|
|
|
programming framework). |
|
|
Let’s revisit Listing 14.8, HandleEvent.java. Since a JButton object fires ActionEvent, a |
||
|
listener object for ActionEvent must be an instance of ActionListener, so the listener |
||
|
class implements ActionListener in line 34. The source object invokes addActionLis- |
||
|
tener(listener) to register a listener, as follows: |
||
create source object |
|
JButton jbtOK = new JButton("OK"); // Line 7 in Listing 14.8 |
|
create listener object |
|
ActionListener listener1 |
|
|
|
= new OKListenerClass(); // Line 18 in Listing 14.8 |
|
register listener |
|
jbtOK.addActionListener(listener1); |
// Line 20 in Listing 14.8 |
|
When you click the button, the JButton object fires an ActionEvent and passes it to invoke |
||
|
the listener’s actionPerformed method to handle the event. |
|
|
16.3 Listeners, Registrations, and Handling Events 537 |
|
TABLE 16.2 Events, Event Listeners, and Listener Methods |
|||
|
|
|
|
Event Class |
Listener Interface |
Listener Methods |
|
(Handlers) |
|
|
|
|
|
|
|
ActionEvent |
ActionListener |
actionPerformed(ActionEvent) |
|
ItemEvent |
ItemListener |
itemStateChanged(ItemEvent) |
|
MouseEvent |
MouseListener |
mousePressed(MouseEvent) |
|
|
|
mouseReleased(MouseEvent) |
|
|
|
mouseEntered(MouseEvent) |
|
|
|
mouseExited(MouseEvent) |
|
|
|
mouseClicked(MouseEvent) |
|
|
MouseMotionListener |
mouseDragged(MouseEvent) |
|
|
|
mouseMoved(MouseEvent) |
|
KeyEvent |
KeyListener |
keyPressed(KeyEvent) |
|
|
|
keyReleased(KeyEvent) |
|
|
|
keyTyped(KeyEvent) |
|
WindowEvent |
WindowListener |
windowClosing(WindowEvent) |
|
|
|
windowOpened(WindowEvent) |
|
|
|
windowIconified(WindowEvent) |
|
|
|
windowDeiconified(WindowEvent) |
|
|
|
windowClosed(WindowEvent) |
|
|
|
windowActivated(WindowEvent) |
|
|
|
windowDeactivated(WindowEvent) |
|
ContainerEvent |
ContainerListener |
componentAdded(ContainerEvent) |
|
|
|
componentRemoved(ContainerEvent) |
|
ComponentEvent |
ComponentListener |
componentMoved(ComponentEvent) |
|
|
|
componentHidden(ComponentEvent) |
|
|
|
componentResized(ComponentEvent) |
|
|
|
componentShown(ComponentEvent) |
|
FocusEvent |
FocusListener |
focusGained(FocusEvent) |
|
|
|
focusLost(FocusEvent) |
|
AdjustmentEvent |
AdjustmentListener |
adjustmentValueChanged(AdjustmentEvent) |
|
ChangeEvent |
ChangeListener |
stateChanged(ChangeEvent) |
|
ListSelectionEvent ListSelectionListener |
valueChanged(ListSelectionEvent) |
The event object contains information pertinent to the event, which can be obtained using the methods, as shown in Figure 16.5. For example, you can use e.getSource() to obtain the source object in order to determine whether it is a button, a check box, or a radio button. For an action event, you can use e.getWhen() to obtain the time when the event occurs.
538 Chapter 16 Event-Driven Programming
source: SourceClass
+addXListener(XListener listener) |
|
|
An event is |
Store in a list |
|
triggered |
||
|
event: XEvent listener1
Invoke listener2 listener1.handler(event) ...
listener2.handler(event) listenern
...
listenern.handler(event)
(a) Internal function of a generic source object
source: javax.swing.JButton
+addActionListener(ActionListener listener) |
|
|
An event is |
Store in a list |
|
triggered |
||
|
event: listener1
ActionEvent Invoke listener2 listener1.actionPerformed(event) ...
listener2.actionPerformed(event) listenern
...
listenern.actionPerformed(event)
(b) Internal function of a JButton object
FIGURE 16.4 The source object notifies the listeners of the event by invoking the handler of the listener object.
java.util.EventObject |
|
|
|
|
|
+getSource(): Object |
|
|
|
Returns the source object for the event. |
|
|
|
|
|
|
|
java.awt.event.AWTEvent |
|
|
|
|
|
|
|
|
java.awt.event.ActionEvent |
|
|
|
|
|
+getActionCommand(): String |
|
Returns the command string associated with this action. For a |
|
|
button, its text is the command string. |
+getModifiers(): int |
|
Returns the modifier keys held down during this action event. |
+getWhen(): long |
|
Returns the timestamp when this event occurred. The time is the |
|
|
number of milliseconds since January 1, 1970, 00:00:00 GMT. |
|
|
|
FIGURE 16.5 You can obtain useful information from an event object.
We now write a program that uses two buttons to control the size of a circle, as shown in Figure 16.6.
first version We will develop this program incrementally. First we write a program in Listing 16.1 that displays the user interface with a circle in the center (line 14) and two buttons in the bottom (line 15).
16.3 Listeners, Registrations, and Handling Events 539
FIGURE 16.6 The user clicks the Enlarge and Shrink buttons to enlarge and shrink the size of the circle.
LISTING 16.1 ControlCircle1.java
1 |
import javax.swing.*; |
|
2 |
import java.awt.*; |
|
3 |
|
|
4 |
public class ControlCircle1 extends JFrame { |
|
5 |
private JButton jbtEnlarge = new JButton("Enlarge"); |
buttons |
6private JButton jbtShrink = new JButton("Shrink");
7 |
private CirclePanel canvas = new CirclePanel(); |
circle canvas |
8 |
|
|
9public ControlCircle1() {
10JPanel panel = new JPanel(); // Use the panel to group buttons
11panel.add(jbtEnlarge);
12panel.add(jbtShrink);
13
14this.add(canvas, BorderLayout.CENTER); // Add canvas to center
15this.add(panel, BorderLayout.SOUTH); // Add buttons to the frame
16}
17
18/** Main method */
19public static void main(String[] args) {
20JFrame frame = new ControlCircle1();
21frame.setTitle("ControlCircle1");
22frame.setLocationRelativeTo(null); // Center the frame
23frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
24frame.setSize(200, 200);
25frame.setVisible(true);
26}
27}
28 |
|
|
29 |
class CirclePanel extends JPanel { |
CirclePanel class |
30 |
private int radius = 5; // Default circle radius |
|
31 |
|
|
32 |
/** Repaint the circle */ |
|
33 |
protected void paintComponent(Graphics g) { |
paint the circle |
34super.paintComponent(g);
35g.drawOval(getWidth() / 2 - radius, getHeight() / 2 - radius,
362 * radius, 2 * radius);
37}
38}
How do you use the buttons to enlarge or shrink the circle? When the Enlarge button is clicked, second version you want the circle to be repainted with a larger radius. How can you accomplish this? You can
expand the program in Listing 16.1 into Listing 16.2 with the following features:
1.Define a listener class named EnlargeListener that implements ActionListener (lines 31–35).
2.Create a listener and register it with jbtEnlarge (line 18).
540Chapter 16 Event-Driven Programming
3.Add a method named enlarge() in CirclePanel to increase the radius, then repaint the panel (lines 41–44).
4.Implement the actionPerformed method in EnlargeListener to invoke canvas.enlarge() (line 33).
5.To make the reference variable canvas accessible from the actionPerformed method, define EnlargeListener as an inner class of the ControlCircle2 class (lines 31–35). Inner classes are defined inside another class. We will introduce inner classes in the next section.
6.To avoid compile errors, the CirclePanel class (lines 37–52) now is also defined as an inner class in ControlCircle2,since an old CirclePanel class is already defined in Listing 16.1.
Video Note
Listener and its registration
create/register listener
listener class
CirclePanel class
enlarge method
LISTING 16.2 ControlCircle2.java
1 import javax.swing.*;
2 import java.awt.*;
3 import java.awt.event.*;
4
5 public class ControlCircle2 extends JFrame {
6 private JButton jbtEnlarge = new JButton("Enlarge");
7 private JButton jbtShrink = new JButton("Shrink");
8 private CirclePanel canvas = new CirclePanel();
9
10public ControlCircle2() {
11JPanel panel = new JPanel(); // Use the panel to group buttons
12panel.add(jbtEnlarge);
13panel.add(jbtShrink);
14
15this.add(canvas, BorderLayout.CENTER); // Add canvas to center
16this.add(panel, BorderLayout.SOUTH); // Add buttons to the frame
18jbtEnlarge.addActionListener(new EnlargeListener());
19 }
20
21/** Main method */
22public static void main(String[] args) {
23JFrame frame = new ControlCircle2();
24frame.setTitle("ControlCircle2");
25frame.setLocationRelativeTo(null); // Center the frame
26frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
27frame.setSize(200, 200);
28frame.setVisible(true);
29}
30
31class EnlargeListener implements ActionListener { // Inner class
32public void actionPerformed(ActionEvent e) {
33canvas.enlarge();
34}
35}
36
37class CirclePanel extends JPanel { // Inner class
38private int radius = 5; // Default circle radius
40/** Enlarge the circle */
41public void enlarge() {
42radius++;