Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
222 views

Core Java AWT and Swings

The document discusses Java's AWT and Swing graphical user interface (GUI) APIs. It introduces AWT components like Frame, Panel, and Dialog containers as well as GUI components like Button and Label. It describes how containers hold and arrange components using layout managers. The document then discusses event handling in AWT using listener interfaces and adapter classes before introducing Swing as an enhanced replacement for AWT.

Uploaded by

krishna524
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
222 views

Core Java AWT and Swings

The document discusses Java's AWT and Swing graphical user interface (GUI) APIs. It introduces AWT components like Frame, Panel, and Dialog containers as well as GUI components like Button and Label. It describes how containers hold and arrange components using layout managers. The document then discusses event handling in AWT using listener interfaces and adapter classes before introducing Swing as an enhanced replacement for AWT.

Uploaded by

krishna524
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 108

Core Java 1

Table of Contents
Java Programming Tutorial.........................................................................................................................................2
Programming Graphical User Interface (GUI)....................................................................................................2
1.  Introduction.....................................................................................................................................................2
2.  Programming GUI with AWT....................................................................................................................2
3.  AWT Event-Handling.................................................................................................................................13
4.  (Advanced) Observer Design Pattern....................................................................................................25
5.  Nested (Inner) Classes................................................................................................................................28
6.  (Advanced) More on Nested Classes......................................................................................................36
7.  Event Listener's Adapter Classes...........................................................................................................43
8.  Layout Managers and Panel.....................................................................................................................45
9.  (Advanced) Composite Design Pattern..................................................................................................50
10.  Swing..............................................................................................................................................................52
11.  Using Visual GUI Builder - NetBeans/Eclipse..................................................................................61

Java Programming Tutorial


Gangadri K Page 1
Core Java 2

Programming Graphical User Interface (GUI)


1.  Introduction
So far, we have covered most of the basic constructs of Java and introduced the important concept of Object-
Oriented Programming (OOP). As discussed, OOP permits higher level of abstraction than the traditional
procedural-oriented languages (such as C and Pascal). OOP lets you think in the problem space rather than the
computer's bits and bytes and instruction sequences. You can create high-level abstract data types calledclasses to
mimic real-life things and represent entities in the problem space. These classes are self-contained and are
reusable.

In this article, I shall show you how you can reuse the graphics classes provided in JDK for constructing your own
Graphical User Interface (GUI) applications. Writing your own graphics classes (re-inventing the wheels) will take
you many years! These graphics classes, developed by expert programmers, are highly complex and involve many
advanced Java concepts.  However, re-using them are not so difficult, if you follow the API documentation,
samples and templates provided.
I shall assume you have a good grasp of OOP, including inheritance and polymorphism (otherwise, read the earlier
articles). I will describe another important concept called nested class (or inner class) in this article.
There are two sets of Java APIs for graphics programming: AWT (Abstract Windowing Toolkit) and Swing.
1. AWT API was introduced in JDK 1.0. Most of the AWT components have become obsolete and should be
replaced by newer Swing components.
2. Swing API, a much more comprehensive set of graphics libraries that enhances the AWT, was introduced as
part of Java Foundation Classes (JFC) after the release of JDK 1.1. JFC consists of Swing, Java2D, Accessibility,
Internationalization, and Pluggable Look-and-Feel Support APIs. JFC was an add-on to JDK 1.1 but has been
integrated into core Java since JDK 1.2.

Other than AWT/Swing Graphics APIs provided in JDK, others have also provided Graphics APIs that work with
Java, such as Eclipse's Standard Widget Toolkit (SWT) (used in Eclipse), Google Web Toolkit (GWT) (used in
Android), 3D Graphics API such as Java bindings for OpenGL (JOGL) and Java3D.
You need to check the JDK API specification (http://docs.oracle.com/javase/7/docs/api/index.html) for the AWT
and Swing APIs while reading this chapter. The best online reference for Graphics programming is the "Swing
Tutorial" @ http://docs.oracle.com/javase/tutorial/uiswing/. For advanced 2D graphics programming, read "Java
2D Tutorial" @ http://docs.oracle.com/javase/tutorial/2d/index.html.
2.  Programming GUI with AWT
Java Graphics APIs - AWT and Swing - provide a huge set of reusable GUI components, such as button, text field,
label, choice, panel and frame for building GUI applications. You can simply reuse these classes rather than re-
invent the wheels. I shall start with the AWT classes before moving into Swing to give you a complete picture. I
have to stress that AWT component classes are now obsoleted by Swing's counterparts.

2.1  AWT Packages
AWT is huge! It consists of 12 packages (Swing is even bigger, with 18 packages as of JDK 1.7!). Fortunately, only 2
packages - java.awt andjava.awt.event - are commonly-used.
1. The java.awt package contains the core AWT graphics classes:
o GUI Component classes (such as Button, TextField, and Label),
o GUI Container classes (such as Frame, Panel, Dialog and ScrollPane),
o Layout managers (such as FlowLayout, BorderLayout and GridLayout),
o Custom graphics classes (such as Graphics, Color and Font).
2. The java.awt.event package supports event handling:
o Event classes (such as ActionEvent, MouseEvent, KeyEvent and WindowEvent),
Gangadri K Page 2
Core Java 3

o Event Listener Interfaces (such as ActionListener, MouseListener, KeyListener and WindowListener),


o Event Listener Adapter classes (such as MouseAdapter, KeyAdapter, and WindowAdapter).
AWT provides a platform-independent and device-independent interface to develop graphic programs that runs on
all platforms, such as Windows, Mac, and Linux.
2.2  Containers and Components

There are two types of GUI elements:


1. Component: Components are elementary GUI entities (such as Button, Label, andTextField.)
2. Container: Containers (such as Frame,Panel and Applet) are used to hold components in a specific
layout (such as flow or grid). A container can also hold sub-containers.
GUI components are also called controls (Microsoft ActiveX Control), widgets (Eclipse's Standard Widget Toolkit,
Google Web Toolkit), which allow users to interact with (i.e., control) the application through these components
(such as button-click and text-entry).
In the above figure, there are three containers: a Frame and two Panels. A Frame is the top-level container of an
AWT program. A Frame has a title bar (containing an icon, a title, and the minimize/maximize/close buttons), an
optional menu bar and the content display area. A Panel is a rectangular areaused to group related GUI
components in a certain layout. In the above figure, the top-level Frame contains two Panels. There are five
components: aLabel (providing description), a TextField (for users to enter text), and three Buttons (for user to
trigger certain programmed actions).
In a GUI program, a component must be kept in a container. You need to identify a container to hold the
components. Every container has a method called add(Component c). A container (say aContainer) can
invoke aContainer.add(aComponent) to add aComponent into itself. For example,
Panel panel = new Panel(); // Panel is a Container
Button btn = new Button("Press"); // Button is a Component
panel.add(btn); // The Panel Container adds a Button Component

2.3  AWT Container Classes
Top-Level Containers: Frame, Dialog and Applet
Each GUI program has a top-level container. The commonly-used top-level containers in AWT
are Frame, Dialog and Applet:

 A Frame provides the "main


window" for the GUI application, which has a title bar (containing an icon, a title, the minimize,

Gangadri K Page 3
Core Java 4

maximize/restore-down and close buttons), an optional menu bar, and the content display area. To write a
GUI program, we typically start with a subclass extending from java.awt.Frame to inherit the main window as
follows:
 import java.awt.Frame; // Using Frame class in package java.awt

 // A GUI program is written as a subclass of Frame - the top-level container
 // This subclass inherits all properties from Frame, e.g., title, icon, buttons, content-
pane
 public class MyGUIProgram extends Frame {

 // Constructor to setup the GUI components
 public MyGUIProgram() { ...... }

 // Other methods
 ......
 ......

 // The entry main() method
 public static void main(String[] args) {
 // Invoke the constructor (to setup the GUI) by allocating an instance
 new MyGUIProgram();
 }

 An AWT Dialog is a "pop-up window" used for interacting with


the users. A Dialog has a title-bar (containing an icon, a title and a close button) and a content display area,
as illustrated.
 An AWT Applet (in package java.applet) is the top-level container for an applet, which is a Java program
running inside a browser. Applet will be discussed in the later chapter.
Secondary Containers: Panel and ScrollPane

Secondary containers are placed inside a top-level container or another secondary container. AWT also provide
these secondary containers:
 Panel: a rectangular box under a higher-level container, used to layout a set of related GUI components in
pattern such as grid or flow.
 ScrollPane: provides automatic horizontal and/or vertical scrolling for a single child component.

 others.
Hierarchy of the AWT Container Classes
The hierarchy of the AWT Container classes is as follows:

Gangadri K Page 4
Core Java 5

As illustrated, each Container has a layout.


2.4  AWT Component Classes
AWT provides many ready-made and reusable GUI components. The frequently-used
are: Button, TextField, Label, Checkbox, CheckboxGroup(radio buttons), List, and Choice, as illustrated below.

AWT GUI Component: java.awt.Label

A java.awt.Label provides a text description message. Take note that System.out.println() prints to the


system console, not to the graphics screen. You could use a Label to label another component (such as text field)
or provide a text description.
Check the JDK API specification for java.awt.Label.
Constructors
public Label(String strLabel, int alignment); // Construct a Label with the given text String,
of the text alignment
public Label(String strLabel); // Construct a Label with the given text String
public Label(); // Construct an initially empty Label

The Label class has three constructors:


1. The first constructor constructs a Label object with the given text string in the given alignment. Note that
three static constants Label.LEFT,Label.RIGHT, and Label.CENTER are defined in the class for you to
specify the alignment (rather than asking you to memorize arbitrary integer values).
2. The second constructor constructs a Label object with the given text string in default of left-aligned.
3. The third constructor constructs a Label object with an initially empty string. You could set the label text via
the setText() method later.
Constants

Gangadri K Page 5
Core Java 6

public static final LEFT; // Label.LEFT


public static final RIGHT; // Label.RIGHT
public static final CENTER; // Label.CENTER

These three constants are defined for specifying the alignment of the Label's text.
Public Methods
// Examples
public String getText();
public void setText(String strLabel);
public int getAlignment();
public void setAlignment(int alignment);

The getText() and setText() methods can be used to read and modify the Label's text. Similarly,


the getAlignment() and setAlignment()methods can be used to retrieve and modify the alignment of the text.
Constructing a Component and Adding the Component into a Container

Three steps are necessary to create and place a GUI component:


1. Declare the component with an identifier (name);
2. Construct the component by invoking an appropriate constructor via the new operator;
3. Identify the container (such as Frame or Panel) designed to hold this component. The container can then
add this component onto itself via aContainer.add(aComponent) method. Every container has
a add(Component) method. Take note that it is the container that actively and explicitly adds a component
onto itself, instead of the other way.

Example

Label lblInput; // Declare an Label instance called lblInput


lblInput = new Label("Enter ID"); // Construct by invoking a constructor via the new operator
add(lblInput); // this.add(lblInput) - "this" is typically a subclass of
Frame
lblInput.setText("Enter password"); // Modify the Label's text string
lblInput.getText(); // Retrieve the Label's text string

An Anonymous Instance
You can create a Label without specifying an identifier, called anonymous instance. In the case, the Java compiler
will assign an anonymous identifierfor the allocated object. You will not be able to reference an anonymous
instance in your program after it is created. This is usually alright for a  Labelinstance as there is often no need to
reference a Label after it is constructed.

Example

// Allocate an anonymous Label instance. "this" container adds the instance into itself.
// You CANNOT reference an anonymous instance to carry out further operations.
add(new Label("Enter Name: ", Label.RIGHT));

// Same as
Label lblXxx = new Label("Enter Name: ", Label.RIGHT)); // lblXxx assigned by compiler
add(lblXxx);

AWT GUI Component: java.awt.Button

A java.awt.Button is a GUI component that triggers a certain programmed action upon clicking.

Gangadri K Page 6
Core Java 7

Constructors
public Button(String buttonLabel);
// Construct a Button with the given label
public Button();
// Construct a Button with empty label

The Button class has two constructors. The first constructor creates a Button object with the given label painted
over the button. The second constructor creates a Button object with no label.
Public Methods

public String getLabel();


// Get the label of this Button instance
public void setLabel(String buttonLabel);
// Set the label of this Button instance
public void setEnable(boolean enable);
// Enable or disable this Button. Disabled Button cannot be clicked.

The getLabel() and setLabel() methods can be used to read the current label and modify the label of a button,
respectively.
Note: The latest Swing's JButton replaces getLabel()/setLabel() with getText()/setText() to be consistent
with all the components. We will describe Swing later.
Event
Clicking a button fires a so-called ActionEvent and triggers a certain programmed action. I will explain event-
handling later.
Example
Button btnColor = new Button("Red"); // Declare and allocate a Button instance called btnColor
add(btnColor); // "this" Container adds the Button
...
btnColor.setLabel("green"); // Change the button's label
btnColor.getLabel(); // Read the button's label
...
add(Button("Blue")); // Create an anonymous Button. It CANNOT be referenced later

AWT GUI Component: java.awt.TextField

A java.awt.TextField is single-line text box for users to enter texts. (There is a multiple-line text box
called TextArea.) Hitting the "ENTER" key on a TextField object triggers an action-event.
Constructors
public TextField(String strInitialText, int columns);
// Construct a TextField instance with the given initial text string with the number of
columns.
public TextField(String strInitialText);
// Construct a TextField instance with the given initial text string.
public TextField(int columns);
// Construct a TextField instance with the number of columns.

Public Methods

public String getText();


// Get the current text on this TextField instance

Gangadri K Page 7
Core Java 8

public void setText(String strText);


// Set the display text on this TextField instance
public void setEditable(boolean editable);
// Set this TextField to editable (read/write) or non-editable (read-only)

Event
Hitting the "ENTER" key on a TextField fires a ActionEvent, and triggers a certain programmed action.
Example
TextField tfInput = new TextField(30); // Declare and allocate an TextField instance called
tfInput
add(tfInput); // "this" Container adds the TextField
TextField tfResult = new TextField(); // Declare and allocate an TextField instance called
tfResult
tfResult.setEditable(false) ; // Set to read-only
add(tfResult); // "this" Container adds the TextField
......
// Read an int from TextField "tfInput", square it, and display on "tfResult".
// getText() returns a String, need to convert to int
int number = Integer.parseInt(tfInput.getText());
number *= number;
// setText() requires a String, need to convert the int number to String.
tfResult.setText(number + "");

Take note that getText()/SetText() operates on String. You can convert a String to a primitive, such
as int or double via static methodInteger.parseInt() or Double.parseDouble(). To convert a primitive to
a String, simply concatenate the primitive with an empty String.
2.5  Example 1: AWTCounter

Let's assemble some components together into a simple GUI counter program, as illustrated. It has a top-level
container Frame, which contains three components - a Label "Counter", a non-editable TextField to display the
current count, and a "Count"Button. The TextField displays "0" initially.

Each time you click the button, the counter's value increases by 1.

1import java.awt.*; // Using AWT container and component classes


2import java.awt.event.*; // Using AWT event classes and listener interfaces
3
4// An AWT program inherits from the top-level container java.awt.Frame
5public class AWTCounter extends Frame implements ActionListener {
6 private Label lblCount; // Declare component Label
7 private TextField tfCount; // Declare component TextField
8 private Button btnCount; // Declare component Button
9 private int count = 0; // Counter's value
10
11 /** Constructor to setup GUI components and event handling */

Gangadri K Page 8
Core Java 9

12 public AWTCounter () {
13 setLayout(new FlowLayout());
14 // "super" Frame sets its layout to FlowLayout, which arranges the components
15 // from left-to-right, and flow to next row from top-to-bottom.
16
17 lblCount = new Label("Counter"); // construct Label
18 add(lblCount); // "super" Frame adds Label
19
20 tfCount = new TextField("0", 10); // construct TextField
21 tfCount.setEditable(false); // set to read-only
22 add(tfCount); // "super" Frame adds tfCount
23
24 btnCount = new Button("Count"); // construct Button
25 add(btnCount); // "super" Frame adds Button
26
27 btnCount.addActionListener(this);
28 // Clicking Button source fires ActionEvent
29 // btnCount registers this instance as ActionEvent listener
30
31 setTitle("AWT Counter"); // "super" Frame sets title
32 setSize(250, 100); // "super" Frame sets initial window size
33
34 // System.out.println(this);
35 // System.out.println(lblCount);
36 // System.out.println(tfCount);
37 // System.out.println(btnCount);
38
39 setVisible(true); // "super" Frame shows
40
41 // System.out.println(this);
42 // System.out.println(lblCount);
43 // System.out.println(tfCount);
44 // System.out.println(btnCount);
45 }
46
47 /** The entry main() method */
48 public static void main(String[] args) {
49 // Invoke the constructor to setup the GUI, by allocating an instance
50 AWTCounter app = new AWTCounter();
51 }
52
53 /** ActionEvent handler - Called back upon button-click. */
54 @Override
55 public void actionPerformed(ActionEvent evt) {
56 ++count; // increase the counter value
57 // Display the counter value on the TextField tfCount
58 tfCount.setText(count + ""); // convert int to String
59 }
60}

To exit this program, you have to close the CMD-shell (or press "control-c" on the CMD console); or push the "red-
square" close button in Eclipse's Application Console. This is because we have yet to write the handler for
the Frame's close button. We shall do that in the later example.
Dissecting the AWTCounter.java
 The import statements (Lines 1-2) are needed, as AWT container and component classes, such
as Frame, Button, TextField, and Label, are kept in the java.awt package; while AWT events and event-
listener interfaces, such as ActionEvent and ActionListener are kept in thejava.awt.event package.

Gangadri K Page 9
Core Java 10

 A GUI program needs a top-level container, and is often written as a subclass of  Frame (Line 5). In other
words, this class AWTCounter is a Frame, and inherits all the attributes and behaviors of a Frame, such as the
title bar and content pane.
 Lines 12 to 34 define a constructor, which is used to setup and initialize the GUI components.
 The setLayout() method (in Line 13) is invoked without an object and the dot operator, hence, defaulted to
"this" object, i.e.,this.setLayout(). The setLayout() is inherited from the superclass Frame and is used to
set the layout of the components inside the container Frame. FlowLayout is used in this example, which
arranges the GUI components in left-to-right and flows into next row in a top-to-bottom manner.
 A Label, TextField (non-editable), and Button are constructed. "this" object (subclass of Frame container)
adds these components into it viaadd() inherited from the superclass Frame.
 The setSize() and the setTitle() (Line 31-32) are used to set the initial size and the title of " this" Frame.
The setVisible(true) method (Line 39) is then invoked to show the display.
 The statement btnCount.addActionListener(this)  (Line 27) is used to setup the event-handling
mechanism, which will be discussed in length later. In brief, whenever the button is clicked,
the actionPerformed() will be called. In the actionPerformed() (Lines 54-59), the counter value increases by
1 and displayed on the TextField.
 In the entry main() method (Lines 48-51), an instance of AWTCounter is constructed. The constructor is
executed to initialize the GUI components and setup the event-handling mechanism. The GUI program then
waits for the user input.
Inspecting Container/Components via  toString()
It is interesting to inspect the GUI objects via the toString(), to gain an insight to these classes. (Alternatively, use
a graphic debugger in Eclipse/NetBeans or study the JDK source code.) For example, if we insert the following
code before and after the setvisible():

System.out.println(this);
System.out.println(lblCount);
System.out.println(tfCount);
System.out.println(btnCount);

setVisible(true); // "super" Frame shows

System.out.println(this);
System.out.println(lblCount);
System.out.println(tfCount);
System.out.println(btnCount);

The output (with my comments) are as follows. You could have an insight of the variables defined in the class.

// Before setVisible()
AWTCounter[frame0,0,0,250x100,invalid,hidden,layout=java.awt.FlowLayout,title=AWT
Counter,resizable,normal]
// name (assigned by compiler) is "frame0"; top-left (x,y) at (0,0); width/height is
250x100 (via setSize());
java.awt.Label[label0,0,0,0x0,invalid,align=left,text=Counter]
// name is "Label0"; align is "Label.LEFT" (default); text is "Counter" (assigned in
contructor)
java.awt.TextField[textfield0,0,0,0x0,invalid,text=0,selection=0-0]
// name is "Textfield0"; text is "0" (assigned in contructor)
java.awt.Button[button0,0,0,0x0,invalid,label=Count]
// name is "button0"; label text is "Count" (assigned in contructor)

Gangadri K Page 10
Core Java 11

// Before setVisible(), all components are invalid (top-left (x,y), width/height are
invalid)

// After setVisible(), all components are valid


AWTCounter[frame0,0,0,250x100,layout=java.awt.FlowLayout,title=AWT Counter,resizable,normal]
// valid and visible (not hidden)
java.awt.Label[label0,20,41,58x23,align=left,text=Counter]
// Top-left (x,y) at (20,41) relative to the parent Frame; width/height = 58x23
java.awt.TextField[textfield0,83,41,94x23,text=0,selection=0-0]
// Top-left (x,y) at (83,41) relative to the parent Frame; width/height = 94x23; no text
selected (0-0)
java.awt.Button[button0,182,41,47x23,label=Count]
// Top-left (x,y) at (182,41) relative to the parent Frame; width/height = 47x23

2.6  Example 2: AWTAccumulator

In this example, the top-level container is again the typical java.awt.Frame, which contains 4 components:
a Label "Enter an Integer", a TextField for accepting user input, another Label "The Accumulated Sum is", and
another non-editable TextField for displaying the sum. The components are arranged in FlowLayout.
The program shall accumulate the number entered into the input TextField and display the sum in
the outputTextField.
1import java.awt.*; // Using AWT container and component classes
2import java.awt.event.*; // Using AWT event classes and listener interfaces
3
4// An AWT GUI program inherits from the top-level container java.awt.Frame
5public class AWTAccumulator extends Frame implements ActionListener {
6 private Label lblInput; // Declare input Label
7 private Label lblOutput; // Declare output Label
8 private TextField tfInput; // Declare input TextField
9 private TextField tfOutput; // Declare output TextField
10 private int numberIn; // Input number
11 private int sum = 0; // Accumulated sum, init to 0
12
13 /** Constructor to setup the UI components and event handling */
14 public AWTAccumulator() {
15 setLayout(new FlowLayout());
16 // "super" Frame sets layout to FlowLayout, which arranges the components
17 // from left-to-right, and flow to next row from top-to-bottom.
18
19 lblInput = new Label("Enter an Integer: "); // Construct Label
20 add(lblInput); // "super" Frame adds Label
21
22 tfInput = new TextField(10); // Construct TextField
23 add(tfInput); // "super" Frame adds TextField

Gangadri K Page 11
Core Java 12

24
25 tfInput.addActionListener(this);
26 // Hitting Enter on TextField fires ActionEvent
27 // tfInput (TextField) registers this instance as ActionEvent listener
28
29 lblOutput = new Label("The Accumulated Sum is: "); // allocate Label
30 add(lblOutput); // "super" Frame adds Label
31
32 tfOutput = new TextField(10); // allocate TextField
33 tfOutput.setEditable(false); // read-only
34 add(tfOutput); // "super" Frame adds TextField
35
36 setTitle("AWT Accumulator"); // "super" Frame sets title
37 setSize(350, 120); // "super" Frame sets initial window size
38 setVisible(true); // "super" Frame shows
39 }
40
41 /** The entry main() method */
42 public static void main(String[] args) {
43 // Invoke the constructor to setup the GUI, by allocating an anonymous instance
44 new AWTAccumulator();
45 }
46
47 /** ActionEvent handler - Called back upon hitting enter key on TextField */
48 @Override
49 public void actionPerformed(ActionEvent evt) {
50 // Get the String entered into the TextField tfInput, convert to int
51 numberIn = Integer.parseInt(tfInput.getText());
52 sum += numberIn; // Accumulate numbers entered into sum
53 tfInput.setText(""); // Clear input TextField
54 tfOutput.setText(sum + ""); // Display sum on the output TextField
55 // convert int to String
56 }
57}

Dissecting the AWTAccumulator.java
1. An AWT GUI program extends from java.awt.Frame (Line 5) - the top-level window container.
2. In the constructor (Line 14), we constructs 4 components - 2 java.awt.Label and 2 java.awt.TextFields.
The Frame adds the components, in FlowLayout.
3. tfInput (TextField) is the source object, which fires an ActionEvent upon hitting the Enter
key. tfInput adds this instance as anActionEvent handler (Line 25). The listener class
(this or AWTAccumulator) needs to implement ActionListener interface and provides implementation to
method actionPerformed(). Whenever an user hits Enter on the tfInput (TextField),
the actionPerformed() will be invoked.
Inspecting Container/Components via  toString()
Printing the toString() after setVisible() produces:

AWTAccumulator[frame0,0,0,350x120,layout=java.awt.FlowLayout,title=AWT
Accumulator,resizable,normal]
java.awt.Label[label0,72,41,107x23,align=left,text=Enter an Integer: ]
java.awt.Label[label1,47,69,157x23,align=left,text=The Accumulated Sum is: ]
java.awt.TextField[textfield0,184,41,94x23,text=,editable,selection=0-0]
java.awt.TextField[textfield1,209,69,94x23,text=,selection=0-0]

Gangadri K Page 12
Core Java 13

3.  AWT Event-Handling
Java adopts the so-called "Event-Driven" (or "Event-Delegation") programming model for event-handling, similar
to most of the visual programming languages (such as Visual Basic and Delphi).

In event-driven programming, a piece of event-handling codes is executed (or called back by the graphics
subsystem) when an event has been fired in response to an user input (such as clicking a mouse button or hitting
the ENTER key). This is unlike the procedural model, where codes are executed in a sequential manner.
The AWT's event-handling classes are kept in package java.awt.event.
Three objects are involved in the event-handling: a source, listener(s) and an event object.
The source object (such as Button and Textfield) interacts with the user. Upon triggered, it creates
an event object. This event object will be messaged to all the registered listener object(s), and an appropriate event-
handler method of the listener(s) is called-back to provide the response. In other words,  triggering a source fires an
event to all its listener(s), and invoke an appropriate handler of the listener(s).
To express interest for a certain source's event, the listener(s) must be registered with the source. In other words,
the listener(s) "subscribes" to a source's event, and the source "publishes" the event to all its subscribers upon
activation. This is known as subscribe-publish or observable-observer design pattern.

The sequence of steps is illustrated above:


1. The source object registers its listener(s) for a certain type of event.
Source object fires event event upon triggered. For example, clicking an Button fires an ActionEvent,
mouse-click fires MouseEvent, key-type fires KeyEvent, etc.
How the source and listener understand each other? The answer is via an agreed-upon interface. For
example, if a source is capable of firing an event called XxxEvent (e.g., MouseEvent) involving various
operational modes (e.g., mouse-clicked, mouse-entered, mouse-exited, mouse-pressed, and mouse-
released). Firstly, we need to declare an interface called XxxListener (e.g., MouseListener) containing the
names of the handler methods. Recall that an interface contains only abstract methods without
implementation. For example,
// A MouseListener interface, which declares the signature of the handlers
// for the various operational modes.
public interface MouseListener {
public void mousePressed(MouseEvent evt); // Called back upon mouse-button pressed

Gangadri K Page 13
Core Java 14

public void mouseReleased(MouseEvent evt); // Called back upon mouse-button released


public void mouseClicked(MouseEvent evt); // Called back upon mouse-button clicked
(pressed and released)
public void mouseEntered(MouseEvent evt); // Called back when mouse pointer entered the
component
public void mouseExited(MouseEvent evt); // Called back when mouse pointer exited the
component
}

Secondly, all the listeners interested in the XxxEvent must implement the XxxListener interface. That is, the
listeners must provide their own implementations (i.e., programmed responses) to all the abstract methods
declared in the XxxListener interface. In this way, the listenser(s) can response to these events
appropriately. For example,
// An example of MouseListener, which provides implementation to the handler methods
class MyMouseListener implement MouseListener {
@Override
public void mousePressed(MouseEvent e) {
System.out.println("Mouse-button pressed!");
}

@Override
public void mouseReleased(MouseEvent e) {
System.out.println("Mouse-button released!");
}

@Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse-button clicked (pressed and released)!");
}

@Override
public void mouseEntered(MouseEvent e) {
System.out.println("Mouse-pointer entered the source component!");
}

@Override
public void mouseExited(MouseEvent e) {
System.out.println("Mouse exited-pointer the source component!");
}
}

Thirdly, in the source, we need to maintain a list of listener object(s), and define two
methods: addXxxListener() and removeXxxListener()to add and remove a listener from this list. The
signature of the methods are:

public void addXxxListener(XxxListener l);


public void removeXxxListener(XxxListener l);

Take note that all the listener(s) interested in the XxxEvent must implement the XxxListener interface. That
is, they are sub-type of theXxxListener. Hence, they can be upcasted to XxxListener and passed as the
argument of the above methods.
In summary, we identify the source, the event-listener interface, and the listener object. The listener must
implement the event-listener interface. The source object then registers listener object via
the addXxxListener() method:
aSource.addXxxListener(alistener); // aSource registers aListener for XxxEvent

Gangadri K Page 14
Core Java 15

2. The source is triggered by a user.


3. The source create an XxxEvent object, which encapsulates the necessary information about the activation.
For example, the (x, y) position of the mouse pointer, the text entered, etc.
4. Finally, for each of the listeners in the listener list, the source invokes the appropriate handler on the
listener(s), which provides the programmed response.
In brief, triggering a source fires an event to all its registered listeners, and invoke an appropriate handler of the
listener.
3.1  Revisit Example
1 AWTCounter: ActionEvent and ActionListener Interface
Clicking a Button (or hitting the "Enter" key on a TextField) fires an ActionEvent to all
its ActionEvent listener(s). An ActionEvent listener must implement ActionListener interface, which declares
one abstract method actionPerformed() as follow:

public interface ActionListener {


public void actionPerformed(ActionEvent e);
// Called back upon button-click (on Button), enter-key pressed (on TextField)
}

Here are the event-handling steps:


 We identify btnCount (Button) as the source object.
 Clicking Button fires an ActionEvent to all its ActionEvent listener(s).
 The listener(s) is required to implement ActionListener interface, and override
the actionPerformed() method to provide the response. For simplicity, we choose " this" object
(AWTCounter) as the listener for the ActionEvent. Hence, "this" class is required to
implementActionListener interface and provide the programmed response in the actionPerformed().
 public class AWTCounter extends Frame implements ActionListener {
 // "this" is chosen as the ActionEvent listener, hence, it is required
 // to implement ActionListener interface
 ......

 // Implementing ActionListener interface requires this class to provide implementation
 // to the abstract method actionPerformed() declared in the interface.
 @Override
 public void actionPerformed(ActionEvent evt) {
 // Programmed response upon activation
 // Increment the count value and display on the TextField
 ++count;
 tfCount.setText(count + "");
 }

 The source object registers listener via the addActionListener(). In this example,


the source btnCount (Button) adds "this" object as a listenervia:

btnCount.addActionListener(this);

Note that addActionListener() takes an argument of the type ActionListener. "this", which


implements ActionListener interface (i.e., a subclass of ActionListener), is upcasted and passed to
the addActionListener() method.

Gangadri K Page 15
Core Java 16

 Upon button-click, the btnCount creates an ActionEvent object, and calls back


the actionPerformed(ActionEvent) method of all its registered listener(s) with the ActionEvent object
created:
 ActionEvent evt = new ActionEvent( ...... );

listener.actionPerformed(evt); // for all its listener(s)

The sequence diagram is as follows:

3.2  Revisit Example
2 AWTAccumulator: ActionEvent and ActionListener Interface
In this example,
1. We identify the tfInput (TextField) as the source object.
2. Hitting the "Enter" key on a TextField fires an ActionEvent to all its ActionEvent listener(s).
3. We choose this object as the ActionEvent listener (for simplicity).
4. The source object tfInput (TextField) registers the listener ( this object) via
the tfInput.addActionListener(this).

Gangadri K Page 16
Core Java 17

5. The ActionEvent listener (this class) is required to implement the ActionListener interface, and override


the actionPerformed() method to provide the programmed response upon activation.
3.3  Example 3: WindowEvent and WindowListener Interface

A WindowEvent is fired (to all its WindowEventlisteners) when a window (e.g., Frame) has been opened/closed,
activated/deactivated, iconified/deiconified via the 3 buttons at the top-right corner or other means. The source
ofWindowEvent shall be a top-level window-container such as Frame.
A WindowEvent listener must implement WindowListener interface, which declares 7 abstract event-handling
methods, as follows. Among them, the windowClosing(), which is called back upon clicking the window-close
button, is the most commonly-used.
public void windowClosing(WindowEvent e)
// Called-back when the user attempts to close the window by clicking the window close
button.
// This is the most-frequently used handler.
public void windowOpened(WindowEvent e)
// Called-back the first time a window is made visible.
public void windowClosed(WindowEvent e)
// Called-back when a window has been closed as the result of calling dispose on the window.
public void windowActivated(WindowEvent e)
// Called-back when the Window is set to be the active Window.
public void windowDeactivated(WindowEvent e)
// Called-back when a Window is no longer the active Window.
public void windowIconified(WindowEvent e)
// Called-back when a window is changed from a normal to a minimized state.
public void windowDeiconified(WindowEvent e)
// Called-back when a window is changed from a minimized to a normal state.

The following program added support for "close-window button" to Example 1: AWTCounter.
1import java.awt.*; // Using AWT containers and components
2import java.awt.event.*; // Using AWT events and listener interfaces
3
4// An AWT GUI program inherits the top-level container java.awt.Frame
5public class WindowEventDemo extends Frame
6 implements ActionListener, WindowListener {
7 // This class acts as listener for ActionEvent and WindowEvent
8 // Java supports only single inheritance, where a class can extend
9 // one superclass, but can implement multiple interfaces.
10
11 private TextField tfCount;
12 private Button btnCount;
13 private int count = 0; // Counter's value
14
15 /** Constructor to setup the UI components and event handling */
16 public WindowEventDemo() {
17 setLayout(new FlowLayout()); // "super" Frame sets to FlowLayout
18
19 add(new Label("Counter")); // "super" Frame adds an anonymous Label
20
21 tfCount = new TextField("0", 10); // Allocate TextField

Gangadri K Page 17
Core Java 18

22 tfCount.setEditable(false); // read-only
23 add(tfCount); // "super" Frame adds tfCount
24
25 btnCount = new Button("Count"); // Declare and allocate a Button
26 add(btnCount); // "super" Frame adds btnCount
27
28 btnCount.addActionListener(this);
29 // btnCount fires ActionEvent to its registered ActionEvent listener
30 // btnCount adds "this" object as an ActionEvent listener
31
32 addWindowListener(this);
33 // "super" Frame fires WindowEvent to its registered WindowEvent listener
34 // "super" Frame adds "this" object as a WindowEvent listener
35
36 setTitle("WindowEvent Demo"); // "super" Frame sets title
37 setSize(250, 100); // "super" Frame sets initial size
38 setVisible(true); // "super" Frame shows
39 }
40
41 /** The entry main() method */
42 public static void main(String[] args) {
43 new WindowEventDemo(); // Let the construct do the job
44 }
45
46 /** ActionEvent handler */
47 @Override
48 public void actionPerformed(ActionEvent evt) {
49 ++count;
50 tfCount.setText(count + "");
51 }
52
53 /** WindowEvent handlers */
54 // Called back upon clicking close-window button
55 @Override
56 public void windowClosing(WindowEvent e) {
57 System.exit(0); // Terminate the program
58 }
59
60 // Not Used, but need to provide an empty body
61 @Override
62 public void windowOpened(WindowEvent e) { }
63 @Override
64 public void windowClosed(WindowEvent e) { }
65 @Override
66 public void windowIconified(WindowEvent e) { }
67 @Override
68 public void windowDeiconified(WindowEvent e) { }
69 @Override
70 public void windowActivated(WindowEvent e) { }
71 @Override
72 public void windowDeactivated(WindowEvent e) { }
73}

In this example, we shall modify the earlier AWTCounter example to handle the WindowEvent. Recall that pushing
the "close-window" button on the AWTCounter has no effect, as it did not handle
the WindowEvent of windowClosing(). We included the WindowEvent handling codes in this example.
1. We identify super Frame as the source object.
2. The Frame fires the WindowEvent to all its registered WindowEvent listener(s).
Gangadri K Page 18
Core Java 19

3. We select this object as the WindowEvent listener (for simplicity)


4. We register this object as the WindowEvent listener to the source Frame via
method addWindowListener(this).
5. The WindowEvent listener (this class) is required to implement the WindowListener interface, which
declares 7 abstract
methods:windowOpened(), windowClosed(), windowClosing(), windowActivated(), windowDeactivated(), 
windowIconified() andwindowDeiconified().
6. We override the windowClosing() handler to terminate the program using System.exit(0). We ignore the
other 6 handlers, but required to provide an empty body.

The sequence diagram is as follow:

3.4  Example 4: MouseEvent and MouseListener Interface
A MouseEvent is fired to all its registered listeners, when you press, release, or click (press followed by release) a
mouse-button (left or right button) at the source object; or position the mouse-pointer at (enter) and away (exit)
from the source object.
A MouseEvent listener must implement the MouseListener interface, which declares the following
five abstract methods:

public void mouseClicked(MouseEvent e)


// Called-back when the mouse-button has been clicked (pressed followed by released) on the
source.
public void mousePressed(MouseEvent e)
public void mouseReleased(MouseEvent e)
// Called-back when a mouse-button has been pressed/released on the source.
// A mouse-click invokes mousePressed(), mouseReleased() and mouseClicked().
public void mouseEntered(MouseEvent e)
public void mouseExited(MouseEvent e)
// Called-back when the mouse-pointer has entered/exited the source.

Gangadri K Page 19
Core Java 20

1import java.awt.*;
2import java.awt.event.MouseEvent;
3import java.awt.event.MouseListener;
4
5public class MouseEventDemo extends Frame implements MouseListener {
6
7 // Private variables
8 private TextField tfMouseX; // to display mouse-click-x
9 private TextField tfMouseY; // to display mouse-click-y
10
11 // Constructor - Setup the UI
12 public MouseEventDemo() {
13 setLayout(new FlowLayout()); // "super" frame sets layout
14
15 // Label
16 add(new Label("X-Click: ")); // "super" frame adds component
17
18 // TextField
19 tfMouseX = new TextField(10); // 10 columns
20 tfMouseX.setEditable(false); // read-only
21 add(tfMouseX); // "super" frame adds component
22
23 // Label
24 add(new Label("Y-Click: ")); // "super" frame adds component
25
26 // TextField
27 tfMouseY = new TextField(10);
28 tfMouseY.setEditable(false); // read-only
29 add(tfMouseY); // "super" frame adds component
30
31 addMouseListener(this);
32 // "super" frame fires the MouseEvent
33 // "super" frame adds "this" object as MouseEvent listener
34
35 setTitle("MouseEvent Demo"); // "super" Frame sets title
36 setSize(350, 100); // "super" Frame sets initial size
37 setVisible(true); // "super" Frame shows
38 }
39
40 public static void main(String[] args) {
41 new MouseEventDemo(); // Let the constructor do the job
42 }
43
44 // MouseEvent handlers
45 @Override
46 public void mouseClicked(MouseEvent e) {
47 tfMouseX.setText(e.getX() + "");
48 tfMouseY.setText(e.getY() + "");

Gangadri K Page 20
Core Java 21

49 }
50
51 @Override
52 public void mousePressed(MouseEvent e) { }
53 @Override
54 public void mouseReleased(MouseEvent e) { }
55 @Override
56 public void mouseEntered(MouseEvent e) { }
57 @Override
58 public void mouseExited(MouseEvent e) { }
59}

In this example, we setup a GUI with 4 components (two Labels and two non-editable TextFields), inside a top-
level container Frame, arranged inFlowLayout.
To demonstrate the MouseEvent:
1. We identity super Frame as the source object.
2. The Frame fires a MouseEvent to all its MouseEvent listener(s) when you click/press/release a mouse-button
or enter/exit with the mouse-pointer.
3. We select this object as the MouseEvent listener (for simplicity).
4. We register this object as the MouseEvent listener to super Frame (source) via the
method addMouseListener(this).
5. The listener (this class) is required to implement the MouseListener interface, which declares 5 abstract
methods: mouseClicked(),mousePressed(), mouseReleased(), mouseEntered(), and mouseExit(). We
override the mouseClicked() to display the (x, y) co-ordinates of the mouse click on the two
displayed TextFields. We ignore all the other handlers (for simplicity - but you need to provide an empty
body for compilation).
Try:  Include a WindowListener to handle the close-window button.
3.5  Example 5: MouseEvent and MouseMotionListener Interface
A MouseEvent is also fired when you moved and dragged the mouse pointer at the source object. But you need to
use MouseMotionListener to handle the mouse-move and mouse-drag. The MouseMotionListener interface
declares the following two abstract methods:

public void mouseDragged(MouseEvent e)


// Called-back when a mouse-button is pressed on the source component and then dragged.
public void mouseMoved(MouseEvent e)
// Called-back when the mouse-pointer has been moved onto the source component but no buttons
have been pushed.

1import java.awt.*;
2import java.awt.event.MouseEvent;
3import java.awt.event.MouseListener;
4import java.awt.event.MouseMotionListener;
5
6// An AWT GUI program inherits from the top-level container java.awt.Frame
7public class MouseMotionDemo extends Frame
8 implements MouseListener, MouseMotionListener {
9 // This class acts as MouseListener and MouseMotionListener
10

Gangadri K Page 21
Core Java 22

11 // To display the (x, y) coordinates of the mouse-clicked


12 private TextField tfMouseClickX;
13 private TextField tfMouseClickY;
14 // To display the (x, y) coordinates of the current mouse-pointer position
15 private TextField tfMousePositionX;
16 private TextField tfMousePositionY;
17
18 /** Constructor to setup the GUI */
19 public MouseMotionDemo() {
20 setLayout(new FlowLayout()); // "this" frame sets to FlowLayout
21
22 add(new Label("X-Click: "));
23 tfMouseClickX = new TextField(10);
24 tfMouseClickX.setEditable(false);
25 add(tfMouseClickX);
26 add(new Label("Y-Click: "));
27 tfMouseClickY = new TextField(10);
28 tfMouseClickY.setEditable(false);
29 add(tfMouseClickY);
30
31 add(new Label("X-Position: "));
32 tfMousePositionX = new TextField(10);
33 tfMousePositionX.setEditable(false);
34 add(tfMousePositionX);
35 add(new Label("Y-Position: "));
36 tfMousePositionY = new TextField(10);
37 tfMousePositionY.setEditable(false);
38 add(tfMousePositionY);
39
40 addMouseListener(this);
41 addMouseMotionListener(this);
42 // "super" frame fires MouseEvent to all its registered MouseListener and MouseMotionListene
43 // "super" frame adds "this" object as MouseListener and MouseMotionListener
44
45 setTitle("MouseMotion Demo"); // "super" Frame sets title
46 setSize(400, 120); // "super" Frame sets initial size
47 setVisible(true); // "super" Frame shows
48 }
49
50 /** The entry main() method */
51 public static void main(String[] args) {
52 new MouseMotionDemo(); // Let the constructor do the job
53 }
54
55 /** MouseListener handlers */
56 // Called back when a mouse-button has been clicked
57 @Override
58 public void mouseClicked(MouseEvent e) {
59 tfMouseClickX.setText(e.getX() + "");
60 tfMouseClickY.setText(e.getY() + "");
61 }
62
63 // Not Used, but need to provide an empty body for compilation
64 @Override
65 public void mousePressed(MouseEvent e) { }
66 @Override
67 public void mouseReleased(MouseEvent e) { }
68 @Override

Gangadri K Page 22
Core Java 23

69 public void mouseEntered(MouseEvent e) { }


70 @Override
71 public void mouseExited(MouseEvent e) { }
72
73 /** MouseMotionEvent handlers */
74 // Called back when the mouse-pointer has been moved
75 @Override
76 public void mouseMoved(MouseEvent e) {
77 tfMousePositionX.setText(e.getX() + "");
78 tfMousePositionY.setText(e.getY() + "");
79 }
80
81 // Not Used, but need to provide an empty body for compilation
82 @Override
83 public void mouseDragged(MouseEvent e) { }
84}

In this example, we shall illustrate both the MouseListener and MouseMotionListener.


1. We identify super Frame as the source, which fires the MouseEvent to its
registered MouseListener and MouseMotionListener.
2. We select this object as the MouseListener and MouseMotionListner (for simplicity).
3. We register this object as the listener to super Frame via
method addMouseListener(this) and addMouseMotionListener(this).
4. The MouseMotionListener (this class) needs to implement 2 abstract
methods: mouseMoved() and mouseDragged() declared in theMouseMotionListener interface.
5. We override the mouseMoved() to display the (x, y) position of the mouse pointer. We ignore
the MouseDragged() handler by providing an empty body for compilation.
Try:  Include a WindowListener to handle the close-window button.
3.6  Example 6: KeyEvent and KeyListener Interface
A KeyEvent is fired (to all its registered KeyListeners) when you pressed, released, and typed (pressed followed
by released) a key on the source object. A KeyEvent listener must implement KeyListener interface, which
declares three abstract methods:

public void keyTyped(KeyEvent e)


// Called-back when a key has been typed (pressed and released).
public void keyPressed(KeyEvent e)
public void keyReleased(KeyEvent e)
// Called-back when a key has been pressed/released.

Gangadri K Page 23
Core Java 24

1import java.awt.*;
2import java.awt.event.KeyEvent;
3import java.awt.event.KeyListener;
4
5// An AWT GUI program inherits from the top-level container java.awt.Frame
6public class KeyEventDemo extends Frame implements KeyListener {
7 // This class acts as KeyEvent Listener
8
9 private TextField tfInput; // single-line TextField to receive tfInput key
10 private TextArea taDisplay; // multi-line TextArea to taDisplay result
11
12 /** Constructor to setup the GUI */
13 public KeyEventDemo() {
14 setLayout(new FlowLayout()); // "super" frame sets to FlowLayout
15
16 add(new Label("Enter Text: "));
17 tfInput = new TextField(10);
18 add(tfInput);
19 taDisplay = new TextArea(5, 40); // 5 rows, 40 columns
20 add(taDisplay);
21
22 tfInput.addKeyListener(this);
23 // tfInput TextField fires KeyEvent to its registered KeyListeners
24 // tfInput adds "this" object as a KeyEvent listener
25
26 setTitle("KeyEvent Demo"); // "super" Frame sets title
27 setSize(400, 200); // "super" Frame sets initial size
28 setVisible(true); // "super" Frame shows
29 }
30
31 /** The entry main() method */
32 public static void main(String[] args) {
33 new KeyEventDemo(); // Let the constructor do the job
34 }
35
36 /** KeyEvent handlers */
37 // Called back when a key has been typed (pressed and released)
38 @Override
39 public void keyTyped(KeyEvent e) {
40 taDisplay.append("You have typed " + e.getKeyChar() + "\n");
41 }
42
43 // Not Used, but need to provide an empty body for compilation
44 @Override
45 public void keyPressed(KeyEvent e) { }
46 @Override
47 public void keyReleased(KeyEvent e) { }
48}

In this example:
1. We identify the tfInput (TextField) as the source object.
2. The source fires a KeyEvent when you press/release/type a key to all its KeyEvent listener(s).
3. We select this object as the KeyEvent listener.
4. We register this object as the KeyEvent listener to the source TextField via
method input.addKeyListener(this).

Gangadri K Page 24
Core Java 25

5. The KeyEvent listener (this class) needs to implement the KeyListener interface, which declares 3 abstract


methods: keyTyped(),keyPressed(), keyReleased().
6. We override the keyTyped() to display key typed on the display TextArea. We ignore
the keyPressed() and keyReleased().
4.  (Advanced) Observer Design Pattern

The Observer design pattern (aka Publish-Subscribe or Observable-Observer) is one of the 23 GoF's design patterns.


Whenever the source's state changes, it notifies all its registered listener.
The source and listener are bound via the interface XxxListener, which defines a set of handlers. The source
maintain a list of registered listeners, and two methods: addXxxListener() and removeXxxListener().
Both addXxxListener() and removeXxxListener() takes an argument ofXxxListener. Hence, a listener object
must implement XxxListener in order to be registered. Whenever the source's state changes, it invokes a
particular handler of all the registered listeners. The interface guarantees the existence of such handler in the
listener.
4.1  Example: Creating Your Own Event, Source and Listener
Suppose that we have a source called Light, with two states - on and off. The source is capable of notifying its
registered listener(s), whenever its state changes.
 First, we define the LightEvent class (extends from java.util.EventObject).
 Next, we define a LightListener interface to bind the source and its listeners. This interface specifies the
signature of the handlers,lightOn(LightEvent) and lightOff(LightEvent).
 In the source Light, we use an ArrayList to maintain its listeners, and create two
methods: addLightListner(LightListener) andremoveLightListener(LightListener) . An method
called notify() is written to invoke the appropriate handlers of each of its registered listeners, whenever the
state of the Light changes.
 A listener class called LightWatcher is written, which implements the LightListener interface and provides
implementation for the handlers.
Event: LightEvent.java
1/** LightEvent */
2import java.util.EventObject;
3
4public class LightEvent extends EventObject {
5 public LightEvent (Object src) {
6 super(src);
7 }
8}

Gangadri K Page 25
Core Java 26

Listener Interface: LightListener.java
1/** The LightListener interface */
2import java.util.EventListener;
3
4public interface LightListener extends EventListener {
5 public void lightOn(LightEvent evt); // called-back upon light on
6 public void lightOff(LightEvent evt); // called-back upon light off
7}

Source: Light.java
1/** The Light Source */
2import java.util.*;
3
4public class Light {
5 // Status - on (true) or off (false)
6 private boolean on;
7 // Listener list
8 private List<LightListener> listeners = new ArrayList<LightListener>();
9
10 /** Constructor */
11 public Light() {
12 on = false;
13 System.out.println("Light: constructed and off");
14 }
15
16 /** Add the given LightListener */
17 public void addLightListener(LightListener listener) {
18 listeners.add(listener);
19 System.out.println("Light: added a listener");
20 }
21
22 /** Remove the given LightListener */
23 public void removeLightListener(LightListener listener) {
24 listeners.remove(listener);
25 System.out.println("Light: removed a listener");
26 }
27
28 /** Turn on this light */
29 public void turnOn() {
30 if (!on) {
31 on = !on;
32 System.out.println("Light: turn on");
33 notify();
34 }
35 }
36
37 /** Turn off this light */
38 public void turnOff() {
39 if (on) {
40 on = !on;
41 System.out.println("Light: turn off");
42 notify();
43 }
44 }
45
46 /** Construct an LightEvent and notify all its registered listeners */
47 private void notify() {

Gangadri K Page 26
Core Java 27

48 LightEvent evt = new LightEvent(this);


49 for (LightListener listener : listeners) {
50 if (on) {
51 listener.lightOn(evt);
52 } else {
53 listener.lightOff(evt);
54 }
55 }
56 }
57}

Listener: LightWatcher.java
1/** An implementation of LightListener class */
2public class LightWatcher implements LightListener {
3 private int id; // ID of this listener
4
5 /** Constructor */
6 public LightWatcher(int id) {
7 this.id = id;
8 System.out.println("LightWatcher-" + id + ": created");
9 }
10
11 /** Implementation of event handlers */
12 @Override
13 public void lightOn(LightEvent evt) {
14 System.out.println("LightWatcher-" + id
15 + ": I am notified that light is on");
16 }
17
18 @Override
19 public void lightOff(LightEvent evt) {
20 System.out.println("LightWatcher-" + id
21 + ": I am notified that light is off");
22 }
23}

A Test Driver: TestLight.java
1/** A Test Driver */
2public class TestLight {
3 public static void main(String[] args) {
4 Light light = new Light();
5 LightWatcher lw1 = new LightWatcher(1);
6 LightWatcher lw2 = new LightWatcher(2);
7 LightWatcher lw3 = new LightWatcher(3);
8 light.addLightListener(lw1);
9 light.addLightListener(lw2);
10 light.turnOn();
11 light.addLightListener(lw3);
12 light.turnOff();
13 light.removeLightListener(lw1);
14 light.removeLightListener(lw3);
15 light.turnOn();
16 }
17}

Below are the expected output:

Light: constructed and off

Gangadri K Page 27
Core Java 28

LightWatcher-1: created
LightWatcher-2: created
LightWatcher-3: created
Light: added a listener
Light: added a listener
Light: turn on
LightWatcher-1: I am notified that light is on
LightWatcher-2: I am notified that light is on
Light: added a listener
Light: turn off
LightWatcher-1: I am notified that light is off
LightWatcher-2: I am notified that light is off
LightWatcher-3: I am notified that light is off
Light: removed a listener
Light: removed a listener
Light: turn on
LightWatcher-2: I am notified that light is on

5.  Nested (Inner) Classes


A nested class (or commonly called inner class) is a class defined inside another class - introduced in JDK 1.1. As an
illustration, two nested classes MyNestedClass1 and MyNestedClass2 are defined inside the definition of an outer
class called MyOuterClass.
public class MyOuterClass { // outer class defined here
......
private class MyNestedClass1 { ... } // an nested class defined inside the outer class
public static class MyNestedClass2 { ... } // an "static" nested class defined inside the
outer class
......
}

A nested class has these properties:


1. A nested class is a proper class. That is, it could contain constructors, member variables and member
methods. You can create an instance of a nested class via the new operator and constructor.
2. A nested class is a member of the outer class, just like any member variables and methods defined inside a
class.
3. Most importantly, a nested class can access the private members (variables/methods) of the enclosing
outer class, as it is at the same level as these private members. This is the property that makes inner class
useful.
4. A nested class can have private, public, protected, or the default access, just like any member variables
and methods defined inside a class. A private inner class is only accessible by the enclosing outer class, and
is not accessible by any other classes. [An top-level outer class cannot be declared private, as no one can
use a private outer class.]
5. A nested class can also be declared static, final or abstract, just like any ordinary class.
6. A nested class is NOT a subclass of the outer class. That is, the nested class does not inherit the variables
and methods of the outer class. It is anordinary self-contained class. [Nonetheless, you could declare it as a
subclass of the outer class, via keyword "extends OuterClassName", in the nested class's definition.]

Gangadri K Page 28
Core Java 29

The usages of nested class are:


1. To control visibilities (of the member variables and methods) between inner/outer class. The nested class,
being defined inside an outer class, can access private members of the outer class.
2. To place a piece of class definition codes closer to where it is going to be used, to make the program clearer
and easier to understand.
3. For namespace management.

5.1  Example 7: A Named Inner Class as Event Listener


A nested class is useful if you need a small class which relies on the enclosing outer class for its private variables
and methods. It is ideal in an event-driven environment for implementing event handlers. This is because the event
handling methods (in a listener) often require access to the private variables (e.g., a private TextField) of the
outer class.
In this example (modified from Example 1 AWTCounter), instead of using "this" as the ActionEvent listener for
the Button, we define a new class called BtnCountListener, and create an instance of BtnCountListener as
the ActionEvent listener for the btnCount. The BtnCountListenerneeds to implement
the ActionListener interface, and override the actionPerformed() handler. Since "this" is no long
a ActionListener, we remove the "implements ActionListener" from "this" class's definition.
BtnCountListener needs to be defined as an inner class, as it needs to access private variables
(count and tfCount) of the outer class.
1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits from the top-level container java.awt.Frame
5public class AWTCounterNamedInnerClass extends Frame {
6 // This class is NOT a ActionListener, hence, it does not implement ActionListener
7
8 // The event-handler actionPerformed() needs to access these "private" variables
9 private TextField tfCount;
10 private int count = 0;
11
12 /** Constructor to setup the GUI */
13 public AWTCounterNamedInnerClass () {
14 setLayout(new FlowLayout()); // "super" Frame sets to FlowLayout
15 add(new Label("Counter")); // anonymous instance of Label
16 tfCount = new TextField("0", 10);
17 tfCount.setEditable(false); // read-only
18 add(tfCount); // "super" Frame adds tfCount
19
20 Button btnCount = new Button("Count");
21 add(btnCount); // "super" Frame adds btnCount
22
23 // Construct an anonymous instance of BtnCountListener (a named inner class).
24 // btnCount adds this instance as a ActionListener.
25 btnCount.addActionListener(new BtnCountListener());
26
27 setTitle("AWT Counter");
28 setSize(250, 100);
29 setVisible(true);
30 }
31
32 /** The entry main method */
33 public static void main(String[] args) {
34 new AWTCounterNamedInnerClass(); // Let the constructor do the job
35 }

Gangadri K Page 29
Core Java 30

36
37 /**
38 * BtnCountListener is a "named inner class" used as ActionListener.
39 * This inner class can access private variables of the outer class.
40 */
41 private class BtnCountListener implements ActionListener {
42 @Override
43 public void actionPerformed(ActionEvent e) {
44 ++count;
45 tfCount.setText(count + "");
46 }
47 }
48}

Dissecting the Program


 An inner class named BtnCountListener is used as the ActionListner.
 An anonymous instance of the BtnCountListener inner class is constructed. The btnCount source object adds
this instance as a listener, as follows:

 btnCount.addActionListener(new BtnCountListener());

 The inner class can access the private variable tfCount and count of the outer class.


 Since "this" is no longer a listener, we remove the " implements ActionListener" from this class' definition.
 The inner class is compiled into AWTCount$BtnCountListener.class, in the format
of OuterClassName$InnerClassName .class.
Using an Ordinary (Outer) Class as Listener
Try moving the BtnCountListener class outside, and define it as an ordinary class. You would need to pass a
reference of the AWTConnter into the constructor of BtnCountListener, and use this reference to access
variables tfCount and count, through public getters or granting them topublic access.
// An ordinary outer class used as ActionListener for the Button
public class BtnCountListener implements ActionListener {
AWTCounter frame;
public BtnCountListener(AWTCounter frame) {
this.frame = frame;
}

@Override
public void actionPerformed(ActionEvent e) {
frame.count++;
frame.tfCount.setText(frame.count + "");
}
}

This code is messy!

5.2  Example 8: An Anonymous Inner Class as Event Listener


Instead of using a named inner class (called BtnCountListner in the previous example), we shall use an inner class
without a name, known asanonymous inner class as the ActionListener in this example.
1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits from the top-level container java.awt.Frame
5public class AWTCounterAnonymousInnerClass extends Frame {
6 // This class is NOT a ActionListener, hence, it does not implement ActionListener
7

Gangadri K Page 30
Core Java 31

8 // The event-handler actionPerformed() needs to access these private variables


9 private TextField tfCount;
10 private int count = 0;
11
12 /** Constructor to setup the GUI */
13 public AWTCounterAnonymousInnerClass () {
14 setLayout(new FlowLayout()); // "super" Frame sets to FlowLayout
15 add(new Label("Counter")); // an anonymous instance of Label
16 tfCount = new TextField("0", 10);
17 tfCount.setEditable(false); // read-only
18 add(tfCount); // "super" Frame adds tfCount
19
20 Button btnCount = new Button("Count");
21 add(btnCount); // "super" Frame adds btnCount
22
23 // Construct an anonymous instance of an anonymous class.
24 // btnCount adds this instance as a ActionListener.
25 btnCount.addActionListener(new ActionListener() {
26 @Override
27 public void actionPerformed(ActionEvent e) {
28 ++count;
29 tfCount.setText(count + "");
30 }
31 });
32
33 setTitle("AWT Counter");
34 setSize(250, 100);
35 setVisible(true);
36 }
37
38 /** The entry main method */
39 public static void main(String[] args) {
40 new AWTCounterAnonymousInnerClass(); // Let the constructor do the job
41 }
42}

Dissecting the Program


 Again, "this" class is NOT used as the ActionEvent listener. Hence, we remove the " implements
ActionListener" from this class' definition.
 The anonymous inner class is given a name generated by the compiler, and compiled
into OuterClassName$n.class, where n is a running number of the inner classes of this outer class.
 An anonymous instance of an anonymous inner class is constructed, and passed as the argument of
the addActionListener() method as follows:
 btnCount.addActionListener(new ActionListener() {
 @Override
 public void actionPerformed(ActionEvent e) {
 ++count;
 tfCount.setText(count + "");
 }

});

The above codes is equivalent to and compiled as:

private class N implements ActionListener { // N is a running number of the inner classes


created
@Override

Gangadri K Page 31
Core Java 32

public void actionPerformed(ActionEvent e) {


++count;
tfCount.setText(count + "");
}
}
btnCount.addActionListener(new N());

// Or
N n = new N()
btnCount.addActionListener(n);

 The above codes create an anonymous instance of an anonymous inner class, and pass it as the argument for
a method. You can also create a named instance of an anonymous inner class, for example,

 // Create an named instance called drawPanel of an anonymous class extends JPanel


 // Upcast to superclass
 JPanel drawPanel = new JPanel() {
 @Override
 public void paintComponent(Graphics g) {
 ......
 }
 }

 // same as
 class N extends JPanel {
 @Override
 public void paintComponent(Graphics g) {
 ......
 }
 }

JPanel drawPanel = new N(); // upcast

Properties of Anonymous Inner Class


1. The anonymous inner class is define inside a method, instead of a member of the outer class (class
member). It is local to the method and cannot be marked with access modifier (such as public, private)
or static, just like any local variable of a method.
2. An anonymous inner class must always extend a superclass or implement an interface. The keyword
"extends" or "implements" is NOT required in its declaration. An anonymous inner class must implement all
the abstract methods in the superclass or in the interface.
3. An anonymous inner class always uses the default (no-arg) constructor from its superclass to create an
instance. If an anonymous inner class implements an interface, it uses the java.lang.Object().
4. An anonymous inner class is compiled into a class named OuterClassName$n.class, where n is a running
number of inner classes within the outer class.
5. An instance of an anonymous inner class is constructed via this syntax:

6. new SuperClassName/InterfaceName() { // extends superclass or implements interface


7. // invoke the default no-arg constructor or Object[]
8. // Implement abstract methods in superclass/interface
9. // More methods if necessary
10. ......

The created instance can be assigned to a variable or used as an argument of a method.

Gangadri K Page 32
Core Java 33

5.3  Example 9: An Anonymous Inner Class for Each Source

Let's modify our AWTCounter example to include 3 buttons for counting up, counting down, and reset the count,
respectively. We shall attach an anonymous inner class as the listener to each of buttons.
1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits the top-level container java.awt.Frame
5public class AWTCounter3Buttons extends Frame {
6 private TextField tfCount;
7 private int count = 0;
8
9 /** Constructor to setup the GUI */
10 public AWTCounter3Buttons () {
11 setLayout(new FlowLayout());
12 add(new Label("Counter")); // an anonymous instance of Label
13 tfCount = new TextField("0", 10);
14 tfCount.setEditable(false); // read-only
15 add(tfCount); // "super" Frame adds tfCount
16
17 Button btnCountUp = new Button("Count Up");
18 add(btnCountUp);
19 // Construct an anonymous instance of an anonymous inner class.
20 // The source Button adds the anonymous instance as ActionEvent listener
21 btnCountUp.addActionListener(new ActionListener() {
22 @Override
23 public void actionPerformed(ActionEvent e) {
24 ++count;
25 tfCount.setText(count + "");
26 }
27 });
28
29 Button btnCountDown = new Button("Count Down");
30 add(btnCountDown);
31 btnCountDown.addActionListener(new ActionListener() {
32 @Override
33 public void actionPerformed(ActionEvent e) {
34 count--;
35 tfCount.setText(count + "");
36 }
37 });
38
39 Button btnReset = new Button("Reset");
40 add(btnReset);
41 btnReset.addActionListener(new ActionListener() {
42 @Override
43 public void actionPerformed(ActionEvent e) {
44 count = 0;
45 tfCount.setText("0");
46 }
47 });
48
49 setTitle("AWT Counter");

Gangadri K Page 33
Core Java 34

50 setSize(400, 100);
51 setVisible(true);
52 }
53
54 /** The entry main method */
55 public static void main(String[] args) {
56 new AWTCounter3Buttons(); // Let the constructor do the job
57 }
58}

Dissecting the Program


1. Each of the Buttons uses an anonymous instance of an anonymous inner class as its ActionEvent listener.
5.4  Example 10: Using the Same Listener Instance for All the Buttons
If you use the same instance as the listener for the 3 buttons, you need to determine which button has fired the
event. It is because all the 3 buttons trigger the same event-handler method.
Using ActionEvent's getActionCommand()
In the following example, we use the same instance of a named inner class as the listener for all the 3 buttons. The
listener needs to determine which button has fired the event. This can be accomplished via
the ActionEvent's getActionCommonad() method, which returns the button's label.
1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits the top-level container java.awt.Frame
5public class AWTCounter3Buttons1Listener extends Frame {
6 private TextField tfCount;
7 private int count = 0;
8
9 /** Constructor to setup the GUI */
10 public AWTCounter3Buttons1Listener () {
11 setLayout(new FlowLayout());
12 add(new Label("Counter"));
13 tfCount = new TextField("0", 10);
14 tfCount.setEditable(false);
15 add(tfCount);
16
17 // Create buttons
18 Button btnCountUp = new Button("Count Up");
19 add(btnCountUp);
20 Button btnCountDown = new Button("Count Down");
21 add(btnCountDown);
22 Button btnReset = new Button("Reset");
23 add(btnReset);
24
25 // Allocate an instance of inner class BtnListener.
26 BtnListener listener = new BtnListener();
27 // Use the same listener to all the 3 buttons.
28 btnCountUp.addActionListener(listener);
29 btnCountDown.addActionListener(listener);
30 btnReset.addActionListener(listener);
31
32 setTitle("AWT Counter");
33 setSize(400, 100);
34 setVisible(true);
35 }
36

Gangadri K Page 34
Core Java 35

37 /** The entry main method */


38 public static void main(String[] args) {
39 new AWTCounter3Buttons1Listener(); // Let the constructor do the job
40 }
41
42 /**
43 * BtnListener is a named inner class used as ActionEvent listener for the buttons.
44 */
45 private class BtnListener implements ActionListener {
46 @Override
47 public void actionPerformed(ActionEvent e) {
48 // Need to determine which button has fired the event.
49 // getActionCommand() returns the button's label
50 String btnLabel = e.getActionCommand();
51 if (btnLabel.equals("Count Up")) {
52 ++count;
53 } else if (btnLabel.equals("Count Down")) {
54 --count;
55 } else {
56 count = 0;
57 }
58 tfCount.setText(count + "");
59 }
60 }
61}

Using getSource() of EventObject
Besides the getActionCommand(), which is only available for ActionEvent, you can use the getSource() method,
which is available to all event objects, to retrieve a reference to the source object that has fired the
event. getSource() returns a java.lang.Object. You may need to downcast it to the proper type of the source
object. For example,
1import java.awt.*;
2import java.awt.event.*;
3
4public class AWTCounter3ButtonsGetSource extends Frame {
5 private TextField tfCount;
6 private Button btnCountUp, btnCountDown, btnReset;
7 private int count = 0;
8
9 /** Constructor to setup the GUI */
10 public AWTCounter3ButtonsGetSource () {
11 setLayout(new FlowLayout());
12 add(new Label("Counter"));
13 tfCount = new TextField("0", 10);
14 tfCount.setEditable(false);
15 add(tfCount);
16
17 // Create buttons
18 btnCountUp = new Button("Count Up");
19 add(btnCountUp);
20 btnCountDown = new Button("Count Down");
21 add(btnCountDown);
22 btnReset = new Button("Reset");
23 add(btnReset);
24
25 // Allocate an instance of inner class BtnListener.
26 BtnListener listener = new BtnListener();

Gangadri K Page 35
Core Java 36

27 // Use the same listener to all the 3 buttons.


28 btnCountUp.addActionListener(listener);
29 btnCountDown.addActionListener(listener);
30 btnReset.addActionListener(listener);
31
32 setTitle("AWT Counter");
33 setSize(400, 100);
34 setVisible(true);
35 }
36
37 /** The entry main method */
38 public static void main(String[] args) {
39 new AWTCounter3ButtonsGetSource(); // Let the constructor do the job
40 }
41
42 /**
43 * BtnListener is a named inner class used as ActionEvent listener for the buttons.
44 */
45 private class BtnListener implements ActionListener {
46 @Override
47 public void actionPerformed(ActionEvent e) {
48 // Need to determine which button has fired the event.
49 Button source = (Button)e.getSource();
50 // Get a reference of the source that has fired the event.
51 // getSource() returns a java.lang.Object. Downcast back to Button.
52 if (source == btnCountUp) {
53 ++count;
54 } else if (source == btnCountDown) {
55 --count;
56 } else {
57 count = 0;
58 }
59 tfCount.setText(count + "");
60 }
61 }
62}

6.  (Advanced) More on Nested Classes


There are 4 types of nested classes:
1. static nested class (as a outer class member),
2. non-static (instance) inner class (as a outer class member),
3. local inner class (defined inside a method),
4. anonymous local inner class (defined inside a method).

6.1  Static vs. Instance Nested Classes


A nested class can be declared static (belonging to the class instead of an instance). Recall that
a static member can be used without instantiating the class and can be referenced via the classname in the form
of Classname.memberName (e.g., Math.PI, Integer.parseInt()). Similarly, a staticnested class can be used
without instantiating the outer class and can be referenced via OuterClassName.InnerClassName .
On the other hand, a non-static nested class belongs to an instance of the outer class, just like any instance
variable or method. It can be referenced via outerClassInstanceName.innerClassInstanceName . A
non-static nested class is formally called an inner class.
Example of non-static (instance) inner class

Gangadri K Page 36
Core Java 37

In this example, a non-static (instance) inner class called MyInnerClass is defined inside the outer class. The
inner class can access private members (variables/methods) of the outer class. This outer class also declares and
constructs an instance of inner class as its member variable.
1public class MyOuterClassWithInnerClass {
2 // Private member variable of the outer class
3 private String msgOuter = "Hello from outer class";
4
5 // Define an inner class as a member of the outer class
6 // This is merely an definition.
7 // Not instantiation takes place when an instance of outer class is constructed
8 public class MyInnerClass {
9 // Private variable of the inner class
10 private String msgInner;
11 // Constructor of the inner class
12 public MyInnerClass(String msgInner) {
13 this.msgInner = msgInner;
14 System.out.println("Constructing an inner class instance: " + msgOuter);
15 // can access private member variable of outer class
16 }
17 // A method of inner class
18 public void printMessage() {
19 System.out.println(msgInner);
20 }
21 }
22
23 // Declare and construct an instance of the inner class, inside the outer class
24 MyInnerClass anInner = new MyInnerClass("Hi from inner class");
25}

Two class files are


produced: MyOuterClassWithInnerClass.class  and MyOuterClassWithInnerClass$MyInnerClass.class .

The following test program:


1. Allocates an instance of outer class, which implicitly allocates an inner class (called anInner) as its member
variable. You can access this inner class via outerClassInstanceName.innerClassInstanceName .
2. Explicitly constructs another instance of the inner class, under the same outer class instance created in the
previous step.
3. Explicitly constructs one more instance of the inner class, under a new instance of outer class. This new outer
class instance also implicitly allocates an inner class instance as its member, as seen from the output.

1public class TestInnerClass {


2 public static void main(String[] args) {
3 // Construct an instance of outer class, which create anInner
4 MyOuterClassWithInnerClass anOuter = new MyOuterClassWithInnerClass();
5 // Invoke inner class's method from this outer class instance
6 anOuter.anInner.printMessage();
7
8 // Explicitly construct another instance of inner class
9 MyOuterClassWithInnerClass.MyInnerClass inner2
10 = anOuter.new MyInnerClass("Inner class 2");
11 inner2.printMessage();
12
13 // Explicitly construct an instance of inner class, under another instance of outer class
14 MyOuterClassWithInnerClass.MyInnerClass inner3
15 = new MyOuterClassWithInnerClass().new MyInnerClass("Inner class 3");

Gangadri K Page 37
Core Java 38

16 inner3.printMessage();
17 }
18}

Constructing an inner class instance: Hello from outer class


Hi from inner class
Constructing an inner class instance: Hello from outer class
Inner class 2
Constructing an inner class instance: Hello from outer class
Constructing an inner class instance: Hello from outer class
Inner class 3

An inner class definition is merely a definition of a class. The outer class does not create an inner class instance,
when it is instantiated. Nonetheless, you could declare it as member of the outer class, as illustrated in the above
example. In many situations, we declare the inner class private. In this cases, the inner class can only be used
(declare and construct) within the outer class.
You can set the inner class to private access. In this case, the inner class can only be accessed within the outer
class, and not by other classes.
Example of static nested class
In this example, a static nested class is defined inside the outer class, which can access
the private static variables of the outer class.
1public class MyOuterClassWithStaticNestedClass {
2 // Private "static" member variable of the outer class
3 private static String msgOuter = "Hello from outer class";
4
5 // Define a "static" nested class as a member of the outer class
6 // It can access private "static" variable of the outer class
7 public static class MyStaticNestedClass {
8 // Private variable of inner class
9 private String msgInner;
10 // Constructor of inner class
11 public MyStaticNestedClass(String msgInner) {
12 this.msgInner = msgInner;
13 System.out.println(msgOuter); // access private member of the outer class
14 }
15 // A method of inner class
16 public void printMessage() {
17 System.out.println(msgInner);
18 }
19 }
20}

You can access the static nested class via the outer classname, in the form
of OuterClassName.NestedClassName , just like any static variables/methods
(e.g., Math.PI, Integer.parseInt()). You can instantiate a static nested class without instantiate the outer class,
as staticmembers are associated with the class, instead of instances.
1public class TestStaticNestedClass {
2 public static void main(String[] args) {
3 // Construct an instance of static nested class
4 // A "static" nested class, like other "static" members, can be accessed via
5 // the Classname.membername
6 MyOuterClassWithStaticNestedClass.MyStaticNestedClass aNestedInner =

Gangadri K Page 38
Core Java 39

7 new MyOuterClassWithStaticNestedClass.MyStaticNestedClass("Hi from inner class");


8 aNestedInner.printMessage();
9 }
10}

Hello from outer class


Hi from inner class

As seen from the example, a static nested class is really like a top-level class with a modified name
(OuterClassname.InnerClassname). It can be used as an extension to package for namespace management.
6.2  Local Inner Class Defined Inside a Method
Java allows you to define an inner class inside a method, just like defining a method's local variable. Like local
variable, a local inner class does not exist until the method is invoked, and goes out of scope when the method
exits.

A local inner class has these properties:


1. A local inner class cannot have access modifier (such as private or public). It also cannot be
declared static.
2. A local inner class can access all the variables/methods of the enclosing outer class.
3. A local inner class can have access to the local variables of the enclosing method only if they are
declared final (to prevent undesirable side-effects).
Example
1public class MyOuterClassWithLocalInnerClass {
2 // Private member variable of the outer class
3 private String msgOuter = "Hello from outer class";
4
5 // A member method of the outer class
6 public void doSomething() {
7
8 // A local variable of the method
9 final String msgMethod = "Hello from method";
10
11 // Define a local inner class inside the method
12 class MyInnerClass {
13 // Private variable of the inner class
14 private String msgInner;
15 // Constructor of the inner class
16 public MyInnerClass(String msgInner) {
17 this.msgInner = msgInner;
18 System.out.println("Constructing an inner class instance: " + msgOuter);
19 // can access private member variable of outer class
20 System.out.println("Accessing final variable of the method: " + msgMethod);
21 // can access final variable of the method
22 }
23 // A method of inner class
24 public void printMessage() {
25 System.out.println(msgInner);
26 }
27 }
28
29 // Create an instance of inner class and invoke its method
30 MyInnerClass anInner = new MyInnerClass("Hi, from inner class");
31 anInner.printMessage();

Gangadri K Page 39
Core Java 40

32 }
33
34 // Test main() method
35 public static void main(String[] args) {
36 // Create an instance of the outer class and invoke the method.
37 new MyOuterClassWithLocalInnerClass().doSomething();
38 }
39}

Constructing an inner class instance: Hello from outer class


Accessing final variable of the method: Hello from method
Hi, from inner class

6.3  An Anonymous Inner Class


An anonymous inner class is a local inner class (of a method) without assigning an explicit classname. It must either
"extends" an existing superclass or "implements" an interface. It is declared and instantiated in one statement via
the new keyword.
Example
1public class MyOuterClassWithAnonymousInnerClass {
2 // Private member variable of the outer class
3 private String msgOuter = "Hello from outer class";
4
5 // A member method of the outer class
6 public void doSomething() {
7 // A local variable of the method
8 final String msgMethod = "Hello from method";
9
10 Thread thread = new Thread() { // create an instance of an anonymous inner class that extends
11 @Override
12 public void run() {
13 System.out.println("Constructing an inner class instance: " + msgOuter);
14 // can access private member variable of outer class
15 System.out.println("Accessing final variable of the method: " + msgMethod);
16 // can access final variable of the method
17 System.out.println("Hi, from inner class!");
18 }
19 };
20 thread.start();
21 }
22
23 // Test main() method
24 public static void main(String[] args) {
25 // Create an instance of the outer class and invoke the method.
26 new MyOuterClassWithAnonymousInnerClass().doSomething();
27 }
28}

Constructing an inner class instance: Hello from outer class


Accessing final variable of the method: Hello from method
Hi, from inner class

The anonymous inner class definition is equivalent to:

public void doSomething()

Gangadri K Page 40
Core Java 41

......
class OuterClassName.n extends Thread { // where n is a running number of anonymous inner
classes
......
}
Thread thread = new OuterClassName.n(); // create an instance of the anonymous inner class
......
}

Clearly, you can only create one instance for each anonymous inner class.

6.4  Example of Static Nested Class in


JDK: Point2D, Point2D.Double, Point2D.Float, Point
The abstract class Point2D (in package java.awt.geom of Java 2D API), which models a 2D point,
declares abstract methods such as getX() andgetY(). The Point2D cannot be instantiated. Point2D does not
define any instance variable, in particular, the x and y location of the point. This is because it is not sure about
the type of x and y (which could be int, float, or double). The instance variables, therefore, are left to the
implementation subclasses.
Three subclasses were implemented for types of int, float and double, respectively. Point2D cannot be designed
as a pure abstract-method-onlyinterface, as it contains non-abstract methods.
The subclass Point defines instance variables x and y in int precision and provides implementation to abstract
methods such as getX() and getY().Point (of int-precision) is a straight-forward implementation of inheritance
and polymorphism. Point is a legacy class (since JDK 1.1) and retrofitted when Java 2D was introduced.
Two subclasses Point2D.Float and Point2D.Double define instance variables x and y
in float and double precision, respectively. These two subclasses, are also declared as public static nested class
of the outer class Point2D. Since they are static, they can be referenced as Point2D.Double and Point2D.Float.
They are implemented as nested static subclasses within the Point2D outer class to keep the codes together and
for namespace management. There is no access-control (of private variables of the outer class) involved.

package java.awt.geom;
abstract public class Point2D {

// abstract methods
abstract public double getX();
abstract public double getY();
abstract public void setLocation(double x, double y);

public double distance(double x, double y) { ... }


public double distance(Point2D p) { ... }
public static double distance(double x1, double y1, double x2, double y2) { ... }
......

public static class Double extends Point2D {


public double x;
public double y;

public Double(double x, double y) { ... }


@Override public double getX() { return x; }
@Override public double getY() { return y; }
@Override public void setLocation(double x, double y) { ... }
......
}

public static class Float extends Point2D {

Gangadri K Page 41
Core Java 42

public float x;
public float y;
public Double(float x, float y) { ... }
@Override public double getX() { ... }
@Override public double getY() { ... }
@Override public void setLocation(double x, double y) { ... }
public void setLocation(float x, float y) { ... }
......
}
}
package java.awt.geom;
public class Point extends Point2D {
public int x;
public int y;
public Point(int x, int y) { ... }
@Override public double getX() { return x; }
@Override public double getY() { return y; }
@Override public void setLocation(double x, double y) { ... }
......
}

Point2D.Double and Point2D.Float are public static classes. In other words, they can be used directly without


instantiating the outer class, just like any static variable or method (which can be referenced directly via the
classname, e.g., Math.PI, Math.sqrt() and Integer.parseInt()). Since they are subclass of Point2D, they can be
upcast to Point2D.

Point2D.Double p1 = new Point2D.Double(1.1, 2.2);


Point2D.Float p2 = new Point2D.Float(1.1f, 2.2f);
Point p3 = new Point(1, 2);
// Using polymorphism
Point2D p1 = new Point2D.Double(1.1, 2.2); // upcast
Point2D p2 = new Point2D.Float(1.1f, 2.2f); // upcast
Point2D p3 = new Point(1, 2); // upcast

Note: These classes were designed before the introduction of generic in JDK 1.5, which supports the passing of
type as argument.

6.5  "Cannot refer to a non-final variable inside an inner class defined in a


different method"
Java specification 8.1.3: "Any local variable, formal method parameter or exception handler parameter used but not
declared in an inner class must be declared final."
By allowing inner class to access non-final local variables inside a method, the local variable could be modified by
the inner class, and causes a strange side-effect.

Solution:
1. Declare the variable final if permissible.
2. Declare the variable outside the method, e.g., as member variables of the class, instead of a local variable
within a method. Both the method and the inner class could access the variable.
3. Use a wrapper class to wrap the variable inside a class. Declare the instance final.
6.6  Referencing Outer-class's "this" from Inner-class

Gangadri K Page 42
Core Java 43

Inside the inner class, "this" refers to the inner class. To refer to the " this" of the outer class, use
"OuterClassName.this". But you can reference outer class's members directly without this clumsy syntax. For
example,

......
public class MyOuterClassName {
private String msg = "Hello";
......
public MyOuterClassName() { // constructor
......
Button btn = new Button("TEST");
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Need OuterClassName.this to refer to the outer class.
// But can reference outer class members (e.g., msg) directly.
JOptionPane.showMessageDialog(MyOuterClassName.this, msg);
}
});
}
}

7.  Event Listener's Adapter Classes


7.1  Example 11: WindowAdapter for WindowListener
Refer to the WindowEventDemo, a WindowEvent listener is required to implement the WindowListener interface,
which declares 7 abstractmethods. Although we are only interested in windowClosing(), we need to provide an
empty body to the other 6 methods in order to compile the program. This is tedious. For example, we can rewrite
the WindowEventDemo using an inner class implementing ActionListener as follows:
1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits the top-level container java.awt.Frame
5public class WindowEventDemoWithInnerClass extends Frame {
6 private TextField tfCount;
7 private int count = 0;
8
9 /** Constructor to setup the GUI */
10 public WindowEventDemoWithInnerClass () {
11 setLayout(new FlowLayout());
12 add(new Label("Counter"));
13 tfCount = new TextField("0", 10);
14 tfCount.setEditable(false);
15 add(tfCount);
16
17 Button btnCount = new Button("Count");
18 add(btnCount);
19 btnCount.addActionListener(new ActionListener() {
20 @Override
21 public void actionPerformed(ActionEvent evt) {
22 ++count;
23 tfCount.setText(count + "");
24 }
25 });
26
27 // Allocate an anonymous instance of an anonymous inner class

Gangadri K Page 43
Core Java 44

28 // that implements WindowListener.


29 // "this" Frame adds the instance as WindowEvent listener.
30 addWindowListener(new WindowListener() {
31 @Override
32 public void windowClosing(WindowEvent e) {
33 System.exit(0); // terminate the program
34 }
35 // Need to provide an empty body for compilation
36 @Override public void windowOpened(WindowEvent e) { }
37 @Override public void windowClosed(WindowEvent e) { }
38 @Override public void windowIconified(WindowEvent e) { }
39 @Override public void windowDeiconified(WindowEvent e) { }
40 @Override public void windowActivated(WindowEvent e) { }
41 @Override public void windowDeactivated(WindowEvent e) { }
42 });
43
44 setTitle("WindowEvent Demo");
45 setSize(250, 100);
46 setVisible(true);
47 }
48
49 /** The entry main method */
50 public static void main(String[] args) {
51 new WindowEventDemoWithInnerClass(); // Let the constructor do the job
52 }
53}

An adapter class called WindowAdapter is therefore provided, which implements the WindowListener interface and


provides default implementations to all the 7 abstract methods. You can then derive a subclass
from WindowAdapter and override only methods of interest and leave the rest to their default implementation. For
example,
1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits the top-level container java.awt.Frame
5public class WindowEventDemoAdapter extends Frame {
6 private TextField tfCount;
7 private int count = 0;
8
9 /** Constructor to setup the GUI */
10 public WindowEventDemoAdapter () {
11 setLayout(new FlowLayout());
12 add(new Label("Counter"));
13 tfCount = new TextField("0", 10);
14 tfCount.setEditable(false);
15 add(tfCount);
16
17 Button btnCount = new Button("Count");
18 add(btnCount);
19 btnCount.addActionListener(new ActionListener() {
20 @Override
21 public void actionPerformed(ActionEvent evt) {
22 ++count;
23 tfCount.setText(count + "");
24 }
25 });
26

Gangadri K Page 44
Core Java 45

27 // Allocate an anonymous instance of an anonymous inner class


28 // that extends WindowAdapter.
29 // "this" Frame adds the instance as WindowEvent listener.
30 addWindowListener(new WindowAdapter() {
31 @Override
32 public void windowClosing(WindowEvent e) {
33 System.exit(0); // Terminate the program
34 }
35 });
36
37 setTitle("WindowEvent Demo");
38 setSize(250, 100);
39 setVisible(true);
40 }
41
42 /** The entry main method */
43 public static void main(String[] args) {
44 new WindowEventDemoAdapter(); // Let the constructor do the job
45 }
46}

7.2  Other Event-Listener Adapter Classes


Similarly, adapter classes such as MouseAdapter, MouseMotionAdapter, KeyAdapter, FocusAdapter are available
for MouseListener,MouseMotionListener, KeyListener, and FocusListener, respectively.
There is no ActionAdapter for ActionListener, because there is only one abstract method
(i.e. actionPerformed()) declared in theActionListener interface. This method has to be overridden and there is
no need for an adapter.
8.  Layout Managers and Panel
A container has a so-called layout manager to arrange its components. The layout managers provide a level of
abstraction to map your user interface on all windowing systems, so that the layout can be platform-independent.
AWT provides the following layout managers (in
package java.awt): FlowLayout, GridLayout, BorderLayout, GridBagLayout, BoxLayout,CardLayout, and others.
(Swing added more layout manager in package javax.swing, to be described later.)
Container's setLayout()
A container has a setLayout() method to set its layout manager:
// java.awt.Container
public void setLayout(LayoutManager mgr)

To set up the layout of a Container (such as Frame, JFrame, Panel, or JPanel), you have to:


1. Construct an instance of the chosen layout object, via new and constructor, e.g., new FlowLayout())
2. Invoke the setLayout() method of the Container, with the layout object created as the argument;
3. Place the GUI components into the Container using the add() method in the correct order; or into the
correct zones.

For example,

// Allocate a Panel (container)


Panel p = new Panel();
// Allocate a new Layout object. The Panel container sets to this layout.
p.setLayout(new FlowLayout());
// The Panel container adds components in the proper order.
p.add(new JLabel("One"));
p.add(new JLabel("Two"));
p.add(new JLabel("Three"));

Gangadri K Page 45
Core Java 46

......
Container's getLayout()
You can get the current layout via Container's getLayout().

Panel awtPanel = new Panel();


System.out.println(awtPanel.getLayout());
// java.awt.FlowLayout[hgap=5,vgap=5,align=center]

Panel's Initial Layout


Panel (and Swing's JPanel) provides a constructor to set its initial layout manager. It is because a primary function
of Panel is to layout a group of component in a particular layout.
public void Panel (LayoutManager layout)
// Construct a Panel in the given layout
// By default, Panel (and JPanel) has FlowLayout

// For example, create a Panel in BorderLayout


Panel mainPanel = new Panel(new BorderLayout());

8.1  FlowLayout

In the java.awt.FlowLayout, components are arranged from left-to-right inside the container in the order that
they are added (via method aContainer.add(aComponent)). When one row is filled, a new row will be started. The
actual appearance depends on the width of the display window.

Constructors

public FlowLayout();
public FlowLayout(int align);
public FlowLayout(int align, int hgap, int vgap);
// align: FlowLayout.LEFT (or LEADING), FlowLayout.RIGHT (or TRAILING), or FlowLayout.CENTER
// hgap, vgap: horizontal/vertical gap between the components
// By default: hgap=5, vgap=5, align=CENTER

Example

1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits the top-level container java.awt.Frame
5public class AWTFlowLayoutDemo extends Frame {
6 private Button btn1, btn2, btn3, btn4, btn5, btn6;
7
8 /** Constructor to setup GUI components */
9 public AWTFlowLayoutDemo () {
10 setLayout(new FlowLayout());
11 // "this" Frame sets layout to FlowLayout, which arranges the components
12 // from left-to-right, and flow from top-to-bottom.

Gangadri K Page 46
Core Java 47

13
14 btn1 = new Button("Button 1");
15 add(btn1);
16 btn2 = new Button("This is Button 2");
17 add(btn2);
18 btn3 = new Button("3");
19 add(btn3);
20 btn4 = new Button("Another Button 4");
21 add(btn4);
22 btn5 = new Button("Button 5");
23 add(btn5);
24 btn6 = new Button("One More Button 6");
25 add(btn6);
26
27 setTitle("FlowLayout Demo"); // "this" Frame sets title
28 setSize(280, 150); // "this" Frame sets initial size
29 setVisible(true); // "this" Frame shows
30 }
31
32 /** The entry main() method */
33 public static void main(String[] args) {
34 new AWTFlowLayoutDemo(); // Let the constructor do the job
35 }
36}

8.2  GridLayout

In java.awt.GridLayout, components are arranged in a grid (matrix) of rows and columns inside the Container.
Components are added in a left-to-right, top-to-bottom manner in the order they are added (via
method aContainer.add(aComponent)).

Constructors

public GridLayout(int rows, int columns);


public GridLayout(int rows, int columns, int hgap, int vgap);
// By default: rows=1, cols=0, hgap=0, vgap=0

Example

1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits the top-level container java.awt.Frame
5public class AWTGridLayoutDemo extends Frame {
6 private Button btn1, btn2, btn3, btn4, btn5, btn6;
7
8 /** Constructor to setup GUI components */
9 public AWTGridLayoutDemo () {
10 setLayout(new GridLayout(3, 2, 3, 3));
11 // "this" Frame sets layout to 3x2 GridLayout, horizontal and verical gaps of 3 pixels

Gangadri K Page 47
Core Java 48

12
13 // The components are added from left-to-right, top-to-bottom
14 btn1 = new Button("Button 1");
15 add(btn1);
16 btn2 = new Button("This is Button 2");
17 add(btn2);
18 btn3 = new Button("3");
19 add(btn3);
20 btn4 = new Button("Another Button 4");
21 add(btn4);
22 btn5 = new Button("Button 5");
23 add(btn5);
24 btn6 = new Button("One More Button 6");
25 add(btn6);
26
27 setTitle("GridLayout Demo"); // "this" Frame sets title
28 setSize(280, 150); // "this" Frame sets initial size
29 setVisible(true); // "this" Frame shows
30 }
31
32 /** The entry main() method */
33 public static void main(String[] args) {
34 new AWTGridLayoutDemo(); // Let the constructor do the job
35 }
36}

If rows or cols is 0, but not both, then any number of components can be placed in that column or row. If both
the rows and cols are specified, thecols value is ignored. The actual cols is determined by the actual number of
components and rows.
8.3  BorderLayout

In java.awt.BorderLayout, the container is divided into 5 zones: EAST, WEST, SOUTH, NORTH, andCENTER.


Components are added using method aContainer.add(acomponent, aZone), where azone is
either BorderLayout.NORTH (or PAGE_START), BorderLayout.SOUTH (or PAGE_END),BorderLayout.WEST (or LINE_ST
ART), BorderLayout.EAST (or LINE_END), or BorderLayout.CENTER. The
method aContainer.add(aComponent) without specifying the zone adds the component to the CENTER.
You need not add components to all the 5 zones. The NORTH and SOUTH components may be stretched
horizontally; the EAST and WEST components may be stretched vertically; the CENTER component may stretch both
horizontally and vertically to fill any space left over.

Constructors

public BorderLayout();
public BorderLayout(int hgap, int vgap);
// By default hgap=0, vgap=0

Example

Gangadri K Page 48
Core Java 49

1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits the top-level container java.awt.Frame
5public class AWTBorderLayoutDemo extends Frame {
6 private Button btnNorth, btnSouth, btnCenter, btnEast, btnWest;
7
8 /** Constructor to setup GUI components */
9 public AWTBorderLayoutDemo () {
10 setLayout(new BorderLayout(3, 3));
11 // "this" Frame sets layout to BorderLayout,
12 // horizontal and vertical gaps of 3 pixels
13
14 // The components are added to the specified zone
15 btnNorth = new Button("NORTH");
16 add(btnNorth, BorderLayout.NORTH);
17 btnSouth = new Button("SOUTH");
18 add(btnSouth, BorderLayout.SOUTH);
19 btnCenter = new Button("CENTER");
20 add(btnCenter, BorderLayout.CENTER);
21 btnEast = new Button("EAST");
22 add(btnEast, BorderLayout.EAST);
23 btnWest = new Button("WEST");
24 add(btnWest, BorderLayout.WEST);
25
26 setTitle("BorderLayout Demo"); // "this" Frame sets title
27 setSize(280, 150); // "this" Frame sets initial size
28 setVisible(true); // "this" Frame shows
29 }
30
31 /** The entry main() method */
32 public static void main(String[] args) {
33 new AWTBorderLayoutDemo(); // Let the constructor do the job
34 }
35}

8.4  Using Panels as Sub-Container to Organize Components

An AWT Panel is a rectangular pane, which can be used as sub-container to organized a group of related
components in a specific layout (e.g., FlowLayout, BorderLayout). Panels are secondary containers, which shall be
added into a top-level container (such as Frame), or another Panel.
For example, the following figure shows a Frame (in BorderLayout) containing
two Panels, panelResult inFlowLayout and panelButtons in GridLayout. panelResult is added to the NORTH,
and panelButtonsis added to the CENTER.
1import java.awt.*;

Gangadri K Page 49
Core Java 50

2import java.awt.event.*;
3
4// An AWT GUI program inherits the top-level container java.awt.Frame
5public class AWTPanelDemo extends Frame {
6 private Button[] btnNumbers = new Button[10]; // Array of 10 numeric buttons
7 private Button btnHash, btnStar;
8 private TextField tfDisplay;
9
10 /** Constructor to setup GUI components */
11 public AWTPanelDemo () {
12 // Set up display panel
13 Panel panelDisplay = new Panel(new FlowLayout());
14 tfDisplay = new TextField("0", 20);
15 panelDisplay.add(tfDisplay);
16
17 // Set up button panel
18 Panel panelButtons = new Panel(new GridLayout(4, 3));
19 btnNumbers[1] = new Button("1");
20 panelButtons.add(btnNumbers[1]);
21 btnNumbers[2] = new Button("2");
22 panelButtons.add(btnNumbers[2]);
23 btnNumbers[3] = new Button("3");
24 panelButtons.add(btnNumbers[3]);
25 btnNumbers[4] = new Button("4");
26 panelButtons.add(btnNumbers[4]);
27 btnNumbers[5] = new Button("5");
28 panelButtons.add(btnNumbers[5]);
29 btnNumbers[6] = new Button("6");
30 panelButtons.add(btnNumbers[6]);
31 btnNumbers[7] = new Button("7");
32 panelButtons.add(btnNumbers[7]);
33 btnNumbers[8] = new Button("8");
34 panelButtons.add(btnNumbers[8]);
35 btnNumbers[9] = new Button("9");
36 panelButtons.add(btnNumbers[9]);
37 // Can use a loop for the above statements!
38 btnStar = new Button("*");
39 panelButtons.add(btnStar);
40 btnNumbers[0] = new Button("0");
41 panelButtons.add(btnNumbers[0]);
42 btnHash = new Button("#");
43 panelButtons.add(btnHash);
44
45 setLayout(new BorderLayout()); // "this" Frame sets to BorderLayout
46 add(panelDisplay, BorderLayout.NORTH);
47 add(panelButtons, BorderLayout.CENTER);
48
49 setTitle("BorderLayout Demo"); // "this" Frame sets title
50 setSize(200, 200); // "this" Frame sets initial size
51 setVisible(true); // "this" Frame shows
52 }
53
54 /** The entry main() method */
55 public static void main(String[] args) {
56 new AWTPanelDemo(); // Let the constructor do the job
57 }
58}

Gangadri K Page 50
Core Java 51

8.5  BoxLayout
BoxLayout arrange components in a single row or column. It respects components' requests on the minimum sizes.

[TODO] Example and diagram

9.  (Advanced) Composite Design Pattern

As mentioned earlier, there are two groups of classes in the AWT hierarchy: containers and components. A
container (e.g., Frame, Panel, Dialog,java.applet.Applet) holds components (e.g., Label, Button, TextField). A
container (e.g., Frame and Panel) can also hold sub-containers (e.g.Panel). Hence, we have a situation that "a
container can contain containers or components".
This is quite a common problem: e.g., a directory contains (sub)directories or files; a group contains (sub)groups or
elementary elements; the tree structure. A design pattern has been proposed for this problem. A design pattern is a
proven and possibly the best solution for a specific class of problems.
As shown in the class diagram, there are two sets of relationship between Container and Component classes.
1. One-to-many aggregation: A Container contains zero or more Components. Each Component is contained in
exactly one Container.
2. Generalization (or Inheritance): Container is a subclass of Component. In other words, a Container is
a Component, which possesses all the properties of Component and can be substituted in place of
a Component.
Combining both relationships, we have: A Container contains Components. Since a Container is a Component,
a Container can also containContainers. Consequently, a Container can contain Containers and Components.
The Gof calls this recursive composition class design "composite design pattern", which is illustrated as follows:

Gangadri K Page 51
Core Java 52

10.  Swing
10.1  Introduction
Swing is part of the so-called "Java Foundation Classes (JFC)" (have you heard of MFC?), which was introduced in
1997 after the release of JDK 1.1. JFC was subsequently included as an integral part of JDK since JDK 1.2. JFC
consists of:
 Swing API: for advanced graphical programming.
 Accessibility API: provides assistive technology for the disabled.
 Java 2D API: for high quality 2D graphics and images.
 Pluggable look and feel supports.
 Drag-and-drop support between Java and native applications.
The goal of Java GUI programming is to allow the programmer to build GUI that looks good on ALL platforms. JDK
1.0's AWT was awkward and non-object-oriented (using many event.getSource()). JDK 1.1's AWT introduced
event-delegation (event-driven) model, much clearer and object-oriented. JDK 1.1 also introduced inner class and
JavaBeans – a component programming model for visual programming environment (similar to Visual Basic and
Dephi).

Swing appeared after JDK 1.1. It was introduced into JDK 1.1 as part of an add-on JFC (Java Foundation Classes).
Swing is a rich set of easy-to-use, easy-to-understand JavaBean GUI components that can be dragged and
dropped as "GUI builders" in visual programming environment. Swing is now an integral part of Java since JDK 1.2.

10.2  Swing's Features
Swing is huge (consists of 18 API packages as in JDK 1.7) and has great depth. Compared with AWT, Swing
provides a huge and comprehensive collection of reusable GUI components, as shown in the Figure below
(extracted form Swing Tutorial).

Gangadri K Page 52
Core Java 53

The main features of Swing are (extracted from the Swing website):
1. Swing is written in pure Java (except a few classes) and therefore is 100% portable.
2. Swing components are lightweight. The AWT components are heavyweight (in terms of system resource
utilization). Each AWT component has its own opaque native display, and always displays on top of the
lightweight components. AWT components rely heavily on the underlying windowing subsystem of the
native operating system. For example, an AWT button ties to an actual button in the underlying native
windowing subsystem, and relies on the native windowing subsystem for their rendering and processing.
Swing components (JComponents) are written in Java. They are generally not "weight-down" by complex GUI
considerations imposed by the underlying windowing subsystem.
3. Swing components support pluggable look-and-feel. You can choose between Java look-and-feel and
the look-and-feel of the underlying OS(e.g., Windows, UNIX or Mac). If the later is chosen, a Swing button
runs on the Windows looks like a Windows' button and feels like a Window's button. Similarly, a Swing
button runs on the UNIX looks like a UNIX's button and feels like a UNIX's button.

Gangadri K Page 53
Core Java 54

4. Swing supports mouse-less operation, i.e., it can operate entirely using keyboard.


5. Swing components support "tool-tips".
6. Swing components are JavaBeans – a Component-based Model used in Visual Programming (like Visual
Basic). You can drag-and-drop a Swing component into a "design form" using a "GUI builder" and double-
click to attach an event handler.
7. Swing application uses AWT event-handling classes (in package java.awt.event). Swing added some new
classes in packagejavax.swing.event, but they are not frequently used.
8. Swing application uses AWT's layout manager (such as FlowLayout and BorderLayout in
package java.awt). It added new layout managers, such as Springs, Struts, and BoxLayout (in
package javax.swing).
9. Swing implements double-buffering and automatic repaint batching for smoother screen repaint.
10. Swing introduces JLayeredPane and JInternalFrame for creating Multiple Document Interface (MDI)
applications.
11. Swing supports floating toolbars (in JToolBar), splitter control, "undo".
12. Others - check the Swing website.

10.3  Using Swing API


If you understood the AWT programming (such as container/component, event-handling, layout manager),
switching over to Swing (or any other Graphics packages) is straight-forward.
Swing's Components
Compared with the AWT classes (in package java.awt), Swing component classes (in package javax.swing) begin
with a prefix "J", e.g., JButton,JTextField, JLabel, JPanel, JFrame, or JApplet.

Gangadri K Page 54
Core Java 55

The above figure shows the class hierarchy of the swing GUI classes. Similar to AWT, there are two groups of
classes: containers and components. A container is used to hold components. A container can also hold containers
because it is a (subclass of) component.
As a rule, do not mix heavyweight AWT components and lightweight Swing components in the same program, as
the heavyweight components will always be painted on top of the lightweight components.
Swing's Top-Level and Secondary Containers

Just like AWT application, a Swing application requires a top-level container. There are three top-level containers in
Swing:
1. JFrame: used for the application's main window (with an icon, a title, minimize/maximize/close buttons, an
optional menu-bar, and a content-pane), as illustrated.
2. JDialog: used for secondary pop-up window (with a title, a close button, and a content-pane).
3. JApplet: used for the applet's display-area (content-pane) inside a browser’s window.
Similarly to AWT, there are secondary containers (such as JPanel) which can be used to group and layout relevant
components.
The Content-Pane of Swing's Top-Level Container

Gangadri K Page 55
Core Java 56

However, unlike AWT, the JComponents shall not be added onto the top-level container (e.g., JFrame, JApplet)
directly because they are lightweight components. The JComponents must be added onto the so-called content-
pane of the top-level container. Content-pane is in fact a java.awt.Container that can be used to group and
layout components.

You could:
1. get the content-pane via getContentPane() from a top-level container, and add components onto it. For
example,
2. public class TestGetContentPane extends JFrame {
3. // Constructor
4. public TestGetContentPane() {
5. // Get the content-pane of this JFrame, which is a java.awt.Container
6. // All operations, such as setLayout() and add() operate on the content-pane
7. Container cp = this.getContentPane();
8. cp.setLayout(new FlowLayout());
9. cp.add(new JLabel("Hello, world!"));
10. cp.add(new JButton("Button"));
11. ......
12. }
13. .......

14. set the content-pane to a JPanel (the main panel created in your application which holds all your GUI
components) via JFrame'ssetContentPane().
15. public class TestSetContentPane extends JFrame {
16. // Constructor
17. public TestSetContentPane() {
18. // The "main" JPanel holds all the GUI components
19. JPanel mainPanel = new JPanel(new FlowLayout());
20. mainPanel.add(new JLabel("Hello, world!"));
21. mainPanel.add(new JButton("Button"));
22.
23. // Set the content-pane of this JFrame to the main JPanel
24. this.setContentPane(mainPanel);
25. ......
26. }
27. .......

Notes: If a component is added directly into a JFrame, it is added into the content-pane of JFrame instead, i.e.,
// "this" is a JFrame
add(new JLabel("add to JFrame directly"));
// is executed as
getContentPane().add(new JLabel("add to JFrame directly"));

Event-Handling in Swing
Swing uses the AWT event-handling classes (in package java.awt.event). Swing introduces a few new event-
handling classes (in packagejavax.swing.event) but they are not frequently used.
Writing Swing Applications

In summary, to write a Swing application, you have:


1. Use the Swing components with prefix "J" in package javax.swing,
e.g., JFrame, JButton, JTextField, JLabel, etc.

Gangadri K Page 56
Core Java 57

2. A top-level container (such as JFrame or JApplet) is needed. The JComponents should be added directly


onto the top-level container. They shall be added onto the content-pane of the top-level container. You can
retrieve a reference to the content-pane by invoking method getContentPane() from the top-level
container, or set the content-pane to the main JPanel created in your program.
3. Swing applications uses AWT event-handling classes,
e.g., ActionEvent/ActionListener, MouseEvent/MouseListener, etc.
4. Run the constructor in the Event Dispatcher Thread (instead of Main thread) for thread safety, as shown in
the following program template.

10.4  Swing Program Template


1import java.awt.*;
2import java.awt.event.*;
3import javax.swing.*;
4
5// A Swing GUI application inherits from top-level container javax.swing.JFrame
6public class ...... extends JFrame {
7
8 // private variables
9 // ......
10
11 /** Constructor to setup the GUI components */
12 public ......() {
13 Container cp = this.getContentPane();
14
15 // Content-pane sets layout
16 cp.setLayout(new ....Layout());
17
18 // Allocate the GUI components
19 // .....
20
21 // Content-pane adds components
22 cp.add(....);
23
24 // Source object adds listener
25 // .....
26
27 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
28 // Exit the program when the close-window button clicked
29 setTitle("......"); // "this" JFrame sets title
30 setSize(300, 150); // "this" JFrame sets initial size (or pack())
31 setVisible(true); // show it
32 }
33
34 /** The entry main() method */
35 public static void main(String[] args) {
36 // Run GUI codes in Event-Dispatching thread for thread-safety
37 SwingUtilities.invokeLater(new Runnable() {
38 @Override
39 public void run() {
40 new ......(); // Let the constructor do the job
41 }
42 });
43 }
44}

I will explain this template in the following Swing example.

Gangadri K Page 57
Core Java 58

10.5  Swing Example 1: SwingCounter

Let's convert the earlier AWT application example into Swing. Compare the two source files and note the changes
(which are highlighted). The display is shown below. Note the differences in look and feelbetween the AWT GUI
components and Swing's.
1import java.awt.*; // Using AWT containers and components
2import java.awt.event.*; // Using AWT events and listener interfaces
3import javax.swing.*; // Using Swing components and containers
4
5// A Swing GUI application inherits from top-level container javax.swing.JFrame
6public class SwingCounter extends JFrame {
7 private JTextField tfCount; // Use Swing's JTextField instead of AWT's TextField
8 private int count = 0;
9
10 /** Constructor to setup the GUI */
11 public SwingCounter () {
12 // Retrieve the content-pane of the top-level container JFrame
13 // All operations done on the content-pane
14 Container cp = getContentPane();
15 cp.setLayout(new FlowLayout());
16
17 cp.add(new JLabel("Counter"));
18 tfCount = new JTextField("0", 10);
19 tfCount.setEditable(false);
20 cp.add(tfCount);
21
22 JButton btnCount = new JButton("Count");
23 cp.add(btnCount);
24
25 // Allocate an anonymous instance of an anonymous inner class that
26 // implements ActionListener as ActionEvent listener
27 btnCount.addActionListener(new ActionListener() {
28 @Override
29 public void actionPerformed(ActionEvent e) {
30 ++count;
31 tfCount.setText(count + "");
32 }
33 });
34
35 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Exit program if close-window button clicke
36 setTitle("Swing Counter"); // "this" JFrame sets title
37 setSize(300, 100); // "this" JFrame sets initial size
38 setVisible(true); // "this" JFrame shows
39 }
40
41 /** The entry main() method */
42 public static void main(String[] args) {
43 // Run the GUI construction in the Event-Dispatching thread for thread-safety
44 SwingUtilities.invokeLater(new Runnable() {
45 @Override
46 public void run() {

Gangadri K Page 58
Core Java 59

47 new SwingCounter(); // Let the constructor do the job


48 }
49 });
50 }
51}

JFrame's Content-Pane
The JFrams's method getContentPane() returns the content-pane (which is a java.awt.Containter) of
the JFrame. You can then set its layout (the default layout is BorderLayout), and add components into it. For
example,
Container cp = getContentPane(); // Get the content-pane of this JFrame
cp.setLayout(new FlowLayout()); // content-pane sets to FlowLayout
cp.add(new JLabel("Counter")); // content-pane adds a JLabel component
......
cp.add(tfCount); // content-pane adds a JTextField component
......
cp.add(btnCount); // content-pane adds a JButton component

You can also use the JFrame's setContentPane() method to directly set the content-pane to a JPanel (or
a JComponent). For example,

JPanel displayPanel = new JPanel();


this.setContentPane(displayPanel);
// "this" JFrame sets its content-pane to a JPanel directly
.....

// The above is different from:


this.getContentPane().add(displayPanel);
// Add a JPanel into the content-pane. Appearance depends on the JFrame's layout.
JFrame's setDefaultCloseOperation()
Instead of writing a WindowEvent listener with a windowClosing() handler to process the "close-window"
button, JFrame provides a method calledsetDefaultCloseOperation() to sets the default operation when the
user initiates a "close" on this frame. Typically, we choose the option JFrame.EXIT_ON_CLOSE, which terminates the
application via a System.exit().

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Running the GUI Construction Codes on the Event-Dispatching Thread


In the previous examples, we invoke the constructor directly in the entry main() method to setup the GUI
components. For example,
// The entry main method
public static void main(String[] args) {
// Invoke the constructor (by allocating an instance) to setup the GUI
new SwingCounter();
}

The constructor will be executed in the so-called "Main-Program" thread. This may cause multi-threading issues
(such as unresponsive user-interface and deadlock).

It is recommended to execute the GUI setup codes in the so-called "Event-Dispatching" thread, instead of "Main-
Program" thread, for thread-safe operations. Event-dispatching thread, which processes events, should be used
when the codes updates the GUI.

Gangadri K Page 59
Core Java 60

To run the constructor on the event-dispatching thread,


invoke static method SwingUtilities.invokeLater() to asynchronously queue the constructor on the event-
dispatching thread. The codes will be run after all pending events have been processed. For example,

public static void main(String[] args) {


// Run the GUI codes in the Event-dispatching thread for thread-safety
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new SwingCounter(); // Let the constructor do the job
}
});
}

Note: javax.swing.SwingUtilities.invokeLater()  is a cover for java.awt.EventQueue.invokeLater()  (which


is used in the NetBeans' Visual GUI Builder).
At times, for example in game programming, the constructor or the main() may contains non-GUI codes. Hence, it
is a common practice to create a dedicated method called initComponents() (used in NetBeans visual GUI
builder) or createAndShowGUI() (used in Swing tutorial) to handle all the GUI codes (and another method
called initGame() to handle initialization of the game's objects). This GUI init method shall be run in the event-
dispatching thread.
Warning Message "The serialization class does not declare a static final
serialVersionUID field of type long"
This warning message is triggered because java.awt.Frame (via its superclass java.awt.Component) implements
the java.io.Serializableinterface. This interface enables the object to be written out to an output
stream serially (via method writeObject()); and read back into the program (via method readObject()). The
serialization runtime uses a number (called serialVersionUID) to ensure that the object read into the program is
compatible with the class definition, and not belonging to another version.

You have these options:


1. Simply ignore this warning message. If a serializable class does not explicitly declare
a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that
class based on various aspects of the class.
2. Add a serialVersionUID (Recommended), e.g.
private static final long serialVersionUID = 1L; // version 1

3. Suppress this particular warning via annotation @SuppressWarmomgs (in package java.lang) (JDK 1.5):


4. @SuppressWarnings("serial")

public class MyFrame extends JFrame { ...... }

10.6  Swing Example 2: SwingAccumulator


1import java.awt.*; // Using AWT containers and components
2import java.awt.event.*; // Using AWT events and listener interfaces
3import javax.swing.*; // Using Swing components and containers
4
5// A Swing GUI application inherits the top-level container javax.swing.JFrame
6public class SwingAccumulator extends JFrame {
7 private JTextField tfInput, tfOutput;
8 private int numberIn; // input number
9 private int sum = 0; // accumulated sum, init to 0
10
11 /** Constructor to setup the GUI */
12 public SwingAccumulator() {

Gangadri K Page 60
Core Java 61

13 // Retrieve the content-pane of the top-level container JFrame


14 // All operations done on the content-pane
15 Container cp = getContentPane();
16 cp.setLayout(new GridLayout(2, 2, 5, 5));
17
18 add(new JLabel("Enter an Integer: "));
19 tfInput = new JTextField(10);
20 add(tfInput);
21 add(new JLabel("The Accumulated Sum is: "));
22 tfOutput = new JTextField(10);
23 tfOutput.setEditable(false); // read-only
24 add(tfOutput);
25
26 // Allocate an anonymous instance of an anonymous inner class that
27 // implements ActionListener as ActionEvent listener
28 tfInput.addActionListener(new ActionListener() {
29 @Override
30 public void actionPerformed(ActionEvent e) {
31 // Get the String entered into the input TextField, convert to int
32 numberIn = Integer.parseInt(tfInput.getText());
33 sum += numberIn; // accumulate numbers entered into sum
34 tfInput.setText(""); // clear input TextField
35 tfOutput.setText(sum + ""); // display sum on the output TextField
36 }
37 });
38
39 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Exit program if close-window button clicke
40 setTitle("Swing Accumulator"); // "this" Frame sets title
41 setSize(350, 120); // "this" Frame sets initial size
42 setVisible(true); // "this" Frame shows
43 }
44
45 /** The entry main() method */
46 public static void main(String[] args) {
47 // Run the GUI construction in the Event-Dispatching thread for thread-safety
48 SwingUtilities.invokeLater(new Runnable() {
49 @Override
50 public void run() {
51 new SwingAccumulator(); // Let the constructor do the job
52 }
53 });
54 }
55}

11.  Using Visual GUI Builder - NetBeans/Eclipse


If you have a complicated layout for your GUI application, you should use a GUI Builder, such as NetBeans or
Eclipse to layout your GUI components in a drag-and-drop manner, similar to the popular visual languages such as
Visual Basic and Dephi.

Gangadri K Page 61
Core Java 62

More on Swing's JComponents
The class hierarchy of Swing's top-level containers ( JFrame, JDialog, JApplet) are as follows. These top-level
Swing containers are heavyweight, that rely on the underlying windowing subsystem of the native platform.

The class hierarchy of Swing's JComponents is as follows. JComponent and its descendants are lightweight


components.

Gangadri K Page 62
Core Java 63

1.1  ImageIcon

Many Swing's JComponents (such as JLabel and JButton) support a text label and an image icon. For example, the
figure shows three buttons: one with text label, one with an image icon, and one with both text and icon.
The javax.swing.ImageIcon class models an image icon. An ImageIcon is a fixed-size picture, typically small, and
mainly used for decorating GUI components. The ImageIcon class implements javax.swing.Icon interface, and
hence, often upcasted and referenced as Icon.
To construct an ImageIcon, provide the image filename or URL. Image file type of GIF, PNG, JPG and BMP are
supported. For example,
// Construct an ImageIcon from an image filename
String imgFilename = "images/duke.png";
// Can use an absolute filename such as "c:/project/images/nought.gif"
ImageIcon iconDuke = new ImageIcon(imgFilename);

// OR
// Construct an ImageIcon via an image URL (in the form of file://path/filename)
ImageIcon iconDuke = null;
String imgFilename = "images/duke.png";
java.net.URL imgURL = getClass().getClassLoader().getResource(imgFilename);

Gangadri K Page 63
Core Java 64

// Filename always relative to the root of the project (i.e., bin)


// can access resource in a JAR file
if (imgURL != null) {
iconDuke = new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + imgFilename);
}

Using URL is more flexible as it can access resources in a JAR file, and produces an error message if the file does
not exist (which results in a null URL).
Many JComponents (such as JLabel, JButton) accepts an ImageIcon in its constructor, or via
the setIcon() method. For example,

ImageIcon iconDuke = null;


String imgFilename = "images/duke.gif"; // relative to project root (or bin)
URL imgURL = getClass().getClassLoader().getResource(imgFilename);
if (imgURL != null) {
iconDuke = new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + imgFilename);
}

JLabel lbl = new JLabel("The Duke", iconDuke, JLabel.CENTER);


lbl.setBackground(Color.LIGHT_GRAY);
lbl.setOpaque(true);

Container cp = getContentPane();
cp.add(lbl);

An ImageIcon uses an java.awt.Image object to hold the image data. You can retrieve this Image object via
the ImageIcon's getImage() method. The Image object is used in the drawImage() method for custom drawing
(which shall be discussed later).
1.2  Setting the Appearances and Properties of  JComponents
Most of the Swing Components supports these features:
 Text and icon.
 Keyboard short-cut (called mnemonics), e.g., activated via the "Alt" key in Windows System.
 Tool tips: display when the mouse-pointer pauses on the component.
 Look and feel: customized appearance and user interaction for the operating platform.
 Localization: different languages for different locale.
All JComponents (such as JPanel, JLabel, JTextField and JButton) support these set methods to set their
appearances and properties:
// javax.swing.JComponent
public void setBackground(Color bgColor)
// Sets the background color of this component
public void setForeground(Color fgcolor)
// Sets the foreground (text) color of this component
public void setFont(Font font)
// Sets the font used by this component
public void setBorder(Border border)
// Sets the border for this component
public void setPreferredSize(Dimension dim)
public void setMaximumSize(Dimension dim)

Gangadri K Page 64
Core Java 65

public void setMinimumSize(Dimension dim)


// Sets the preferred, maximum or minimum size of this component.
public void setOpaque(boolean isOpaque)
// If true (opaque), fill the background with background color;
// otherwise, enable transparent background.
// Most of the JComponents have default of true, except JLabel.
public void setToolTipText(String toolTipMsg)
// Sets the tool-tip message, to be displayed when the mouse-pointer pauses over the
component.

Swing's JLabel and buttons (AbstractButton subclasses): support both text and icon, which can be specified in
the constructor or via the setters.
// javax.swing.JLabel, javax.swing.AbstractButton
public void setText(String strText)
// Set the text
public void setIcon(Icon defaultIcon)
// Set the button's default icon (you can have different icons for "pressed" and "disabled"
states)
public void setHorizontalAlignment(int alignment)
// Set the horizontal alignment of icon and text
// SwingConstants.RIGHT, SwingConstants.LEFT, SwingConstants.CENTER
public void setVerticalAlignment(int alignment)
// Set the vertical alignment of icon and text,
// SwingConstants.TOP, SwingConstants.BOTTOM, SwingConstants.CENTER
public void setHorizontalTextPosition(int textPosition)
// Set the horizontal text position relative to icon
// SwingConstants.RIGHT, SwingConstants.LEFT, SwingConstants.CENTER, SwingConstants.LEADING,
SwingConstants.TRAILING.
public void setVerticalTextPosition(int textPosition)
// Set the vertical text position relative to icon
// SwingConstants.TOP, SwingConstants.BOTTOM, SwingConstants.CENTER

JTextField supports:
// javax.swing.JTextField, javax.swing.JLabel, javax.swing.AbstractButton
public void setHorizontalAlignment(int alignment)
// Set the text's horizontal alignment: JTextField.LEFT, JTextField.CENTER
// JTextField.RIGHT, JTextField.LEADING, JTextField.TRAILING
// No setVerticalAlignment as text field is single-line

Swing's buttons support mnemonic (to be triggered via keyboard short-cut with alt key).

// javax.swing.AbstractButton
public void setMnemonic(int mnemonic)
// Set the keyboard mnemonic (i.e., the alt short-cut key).
// Use KeyEvent.VK_xxx to specify the key.

Example

Gangadri K Page 65
Core Java 66

This example creates 3 JComponents: a JLabel, a JTextFieldand a JButton, and sets their appearances
(background and foreground colors, font, preferred size and opacity). It also sets the horizontal text alignment for
the JTextField.

Images:

 
1import java.awt.*;
2import java.awt.event.*;
3import java.net.URL;
4import javax.swing.*;
5
6/** Test setting Swing's JComponents properties and appearances */
7@SuppressWarnings("serial")
8public class SwingJComponentSetterTest extends JFrame {
9
10 // Image path relative to the project root (i.e., bin)
11 private String imgCrossFilename = "images/cross.gif";
12 private String imgNoughtFilename = "images/nought.gif";
13
14 /** Constructor to setup the GUI */
15 public SwingJComponentSetterTest() {
16
17 // Prepare ImageIcons to be used with JComponents
18 ImageIcon iconCross = null;
19 ImageIcon iconNought = null;
20 URL imgURL = getClass().getClassLoader().getResource(imgCrossFilename);
21 if (imgURL != null) {
22 iconCross = new ImageIcon(imgURL);
23 } else {
24 System.err.println("Couldn't find file: " + imgCrossFilename);
25 }
26 imgURL = getClass().getClassLoader().getResource(imgNoughtFilename);
27 if (imgURL != null) {
28 iconNought = new ImageIcon(imgURL);
29 } else {
30 System.err.println("Couldn't find file: " + imgNoughtFilename);
31 }
32
33 Container cp = getContentPane();
34 cp.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 10));
35
36 // Create a JLabel with text and icon and set its appearances
37 JLabel label = new JLabel("JLabel", iconCross, SwingConstants.CENTER);
38 label.setFont(new Font(Font.DIALOG, Font.ITALIC, 14));
39 label.setOpaque(true); // needed for JLabel to show the background color
40 label.setBackground(new Color(204, 238, 241)); // light blue
41 label.setForeground(Color.RED); // foreground text color
42 label.setPreferredSize(new Dimension(120, 80));
43 label.setToolTipText("This is a JLabel"); // Tool tip
44 cp.add(label);
45
46 // Create a JButton with text and icon and set its appearances
47 JButton button = new JButton(); // use setter to set text and icon
48 button.setText("Button");
49 button.setIcon(iconNought);

Gangadri K Page 66
Core Java 67

50 button.setVerticalAlignment(SwingConstants.BOTTOM); // of text and icon


51 button.setHorizontalAlignment(SwingConstants.RIGHT); // of text and icon
52 button.setHorizontalTextPosition(SwingConstants.LEFT); // of text relative to icon
53 button.setVerticalTextPosition(SwingConstants.TOP); // of text relative to icon
54 button.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 15));
55 button.setBackground(new Color(231, 240, 248));
56 button.setForeground(Color.BLUE);
57 button.setPreferredSize(new Dimension(150, 80));
58 button.setToolTipText("This is a JButton");
59 button.setMnemonic(KeyEvent.VK_B); // can activate via Alt-B (buttons only)
60 cp.add(button);
61
62 // Create a JTextField with text and icon and set its appearances
63 JTextField textField = new JTextField("Text Field", 15);
64 textField.setFont(new Font(Font.DIALOG_INPUT, Font.PLAIN, 12));
65 textField.setForeground(Color.RED);
66 textField.setHorizontalAlignment(JTextField.RIGHT); // Text alignment
67 textField.setToolTipText("This is a JTextField");
68 cp.add(textField);
69
70 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
71 setTitle("JComponent Test");
72 setLocationRelativeTo(null); // center window on the screen
73 setSize(500, 150); // or pack()
74 setVisible(true);
75
76 // Print description of the JComponents via toString()
77 System.out.println(label);
78 System.out.println(button);
79 System.out.println(textField);
80 }
81
82 /** The entry main() method */
83 public static void main(String[] args) {
84 // Run the GUI codes on Event-Dispatching thread for thread safety
85 SwingUtilities.invokeLater(new Runnable() {
86 @Override
87 public void run() {
88 new SwingJComponentSetterTest(); // Let the constructor do the job
89 }
90 });
91 }
92}

javax.swing.JLabel[, 41, 10, 120x80, alignmentX=0.0, alignmentY=0.0, border=, flags=25165832,


maximumSize=, minimumSize=, preferredSize=java.awt.Dimension[width=120,height=80],
defaultIcon=file:.../cross.gif, disabledIcon=,
horizontalAlignment=CENTER, horizontalTextPosition=TRAILING,
iconTextGap=4, labelFor=, text=JLabel, verticalAlignment=CENTER,
verticalTextPosition=CENTER]
javax.swing.JButton[, 171, 10, 150x80, alignmentX=0.0, alignmentY=0.5,
border=javax.swing.plaf.BorderUIResource$CompoundBorderUIResource@c5e2cf, flags=424,
maximumSize=, minimumSize=, preferredSize=java.awt.Dimension[width=150,height=80],
defaultIcon=file:/.../nought.gif, disabledIcon=, disabledSelectedIcon=,

Gangadri K Page 67
Core Java 68

margin=javax.swing.plaf.InsetsUIResource[top=2,left=14,bottom=2,right=14],
paintBorder=true, paintFocus=true, pressedIcon=, rolloverEnabled=true, rolloverIcon=,
rolloverSelectedIcon=, selectedIcon=, text=Button, defaultCapable=true]
javax.swing.JTextField[, 331, 39, 109x21,
layout=javax.swing.plaf.basic.BasicTextUI$UpdateHandler,
alignmentX=0.0, alignmentY=0.0,
border=javax.swing.plaf.BorderUIResource$CompoundBorderUIResource@1991de1,
flags=296, maximumSize=, minimumSize=, preferredSize=,
caretColor=sun.swing.PrintColorUIResource[r=51,g=51,b=51],
disabledTextColor=javax.swing.plaf.ColorUIResource[r=184,g=207,b=229], editable=true,
margin=javax.swing.plaf.InsetsUIResource[top=0,left=0,bottom=0,right=0],
selectedTextColor=sun.swing.PrintColorUIResource[r=51,g=51,b=51],
selectionColor=javax.swing.plaf.ColorUIResource[r=184,g=207,b=229],
columns=15, columnWidth=7, command=, horizontalAlignment=RIGHT]

The above clearly showed that there are many more properties that can be controlled.

1.3  Display Area, Border and Insets


Display Area
You can use the following get methods to get the dimensions of the display area of a JComponent. Each
component maintains its own co-ordinates with origin (top-left corner) at (0, 0), width and height. You can also get
the origin (x, y) relative to its parent or the screen.

public int getWidth()


public int getHeight()
public Dimension getSize()
// Get the current width or height of the component, measured in pixels.
// The getSize() returns width and height in a Dimension object.
public int getX()
public int getY()
public Point getLocation()
// Get the component's current origin (x, y) relative to the
// parent's (e.g., JPanel or JFrame) upper-left corner, measured in pixels.
// The getLocation() returns the (x, y) in a Point object.
public Point getLocationOnScreen()
// Get the component's current origin (x, y) relative to the screen

For example:

1import java.awt.*;
2import javax.swing.*;
3
4public class TestSize {
5 public static void main(String[] args) {
6 JFrame frame = new JFrame("Display Area");
7 Container cp = frame.getContentPane();
8 cp.setLayout(new FlowLayout());
9 JButton btnHello = new JButton("Hello");
10 btnHello.setPreferredSize(new Dimension(100, 80));
11 cp.add(btnHello);
12

Gangadri K Page 68
Core Java 69

13 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
14 frame.setSize(300, 150); // or pack() the components
15 frame.setLocationRelativeTo(null); // center the application window
16 frame.setVisible(true); // show it
17
18 System.out.println(btnHello.getSize());
19 System.out.println(btnHello.getLocation());
20 System.out.println(btnHello.getLocationOnScreen());
21
22 System.out.println(cp.getSize());
23 System.out.println(cp.getLocation());
24 System.out.println(cp.getLocationOnScreen());
25
26 System.out.println(frame.getSize());
27 System.out.println(frame.getLocation());
28 System.out.println(frame.getLocationOnScreen());
29 }
30}

java.awt.Dimension[width=100,height=80] // JButton's getSize()


java.awt.Point[x=91,y=5] // JButton's getLocation()
java.awt.Point[x=590,y=349] // JButton's getLocationOnScreen()

java.awt.Dimension[width=282,height=105] // ContentPane's getSize()


java.awt.Point[x=0,y=0] // ContentPane's getLocation()
java.awt.Point[x=499,y=344] // ContentPane's getLocationOnScreen()

java.awt.Dimension[width=300,height=150] // JFrame's getSize()


java.awt.Point[x=490,y=308] // JFrame's getLocation()
java.awt.Point[x=490,y=308] // JFrame's getLocationOnScreen()

Border
Swing supports these border types (in package javax.swing.border), which can be applied to all JComponents:
1. EmptyBorder: empty, transparent border which takes up space but does no drawing.
2. LineBorder: line border of arbitrary thickness and of a single color.
3. TitledBorder: with the addition of a String title in a specified position and justification.
4. StrokeBorder: border of an arbitrary stroke.
5. BevelBorder: two-line bevel border.
6. SoftBevelBorder: raised or lowered bevel with softened corners.

Gangadri K Page 69
Core Java 70

7. EtchedBorder: etched-in or etched-out with highlight/shadow.


8. MatteBorder: matte-like border of either a solid color or a tiled icon.
9. CompoundBorder: compose two Borders - inner and outer.
To set a border to a JComponent, the easier way is to choose a static method from the BorderFactory class
(instead of using the constructor of theBorder class). For example,

JPanel panel = new JPanel();


panel.setBorder(BorderFactory.createLineBorder(Color.CYAN, 15));
// Set border to line-border with the given color and thickness

The BorderFactory class provides these static methods to create borders:

public static Border createLineBorder(Color color, [int thickness, boolean rounded])


// Creates a line border with the specified color, thickness, and corner shape.
public static Border createEmptyBorder([int top, int left, int bottom, int right])
// Creates an "empty" border with the given width of the top, left, bottom, and right sides.
public static TitledBorder createTitledBorder(String title)
// Creates a new titled border with the specified title.
public static TitledBorder createTitledBorder(Border border, [String title,
int titleJustification, int titlePosition, Font titleFont, Color titleColor])
// Adds a title to an existing border, with the specified positioning, font and color.
public static CompoundBorder createCompoundBorder([Border outsideBorder, Border insideBorder])
// Creates a compound border specifying the border objects to use for the outside and inside
edges.
MORE: Refer to the API

Borders are included into the display area of a JComponent as illustrated.


To exclude the border, you could use the method getInSets() to retrieve the 4 borders in an Insets object
(saysinsets), and use insets.left,insets.right, insets.top, andinsets.bottom to retrieve the width of the 4
borders. For example,
// Continue from previous example
Insets insets = frame.getInsets();
System.out.println(insets);
// java.awt.Insets[top=36,left=9,bottom=9,right=9]
int realWidth = frame.getWidth() - insets.left - insets.right;
int realHeight = frame.getHeight() - insets.top - insets.bottom;
System.out.println("real width = " + realWidth); // real width = 282
System.out.println("real height = " + realHeight); // real height = 105

Example

Gangadri K Page 70
Core Java 71

This example illustrates the display area, border and the various dimension.

1import java.awt.*;
2import javax.swing.*;
3
4// A Swing application inherits from top-level container javax.swing.JFrame
5public class TestDisplayAreaAndBorder extends JFrame {
6 /** Constructor to setup the GUI */
7 public TestDisplayAreaAndBorder() {
8 Container cp = getContentPane();
9 cp.setLayout(new FlowLayout());
10
11 JTextArea comp = new JTextArea(10, 25); // row and columns
12 comp.setBackground(new Color(200, 200, 200));
13 comp.setForeground(Color.BLUE);
14 comp.setBorder(BorderFactory.createLineBorder(Color.CYAN, 15));
15 // set border to line-border with the given color and thickness
16 comp.setPreferredSize(new Dimension(350, 200));
17 cp.add(comp);
18
19 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
20 setTitle("Appearance and Border");
21 setSize(400, 300);
22 setVisible(true);
23
24 StringBuffer msg = new StringBuffer();
25 msg.append("Width = " + comp.getWidth());
26 msg.append("\nHeight = " + comp.getHeight());
27 msg.append("\nOrigin-X = " + comp.getX());
28 msg.append("\nOrigin-Y = " + comp.getY());
29 msg.append("\nOrigin-X (on screen) = " + comp.getLocationOnScreen().x);
30 msg.append("\nOrigin-Y (on screen) = " + comp.getLocationOnScreen().y);
31
32 Insets insets = comp.getInsets();
33 msg.append("\nInsets (top, right, bottom, left) = "
34 + insets.top + "," + insets.right + "," + insets.bottom + "," + insets.left);
35 msg.append("\nReal Width = " + (comp.getWidth() - insets.left - insets.right));
36 msg.append("\nReal Height = " + (comp.getHeight() - insets.top - insets.bottom));
37
38 comp.setText(msg.toString());

Gangadri K Page 71
Core Java 72

39 }
40
41 /** The entry main() method */
42 public static void main(String[] args) {
43 // Run the GUI codes on Event-Dispatching thread for thread safety
44 SwingUtilities.invokeLater(new Runnable() {
45 @Override
46 public void run() {
47 new TestDisplayAreaAndBorder(); // Let the constructor do the job
48 }
49 });
50 }
51}

1.4  Positioning Your Application Window


You can position your main application window ( JFrame), or top-level container, on the screen, via:
// Set methods (in java.awt.Window)
// (x, y) specifies the origin (top-left corner) of the window on the screen
public void setSize(int width, int height)
public void setLocation(int x, int y)
public void setBounds(int x, int y, int width, int height)
public void setSize(Dimension dim)
public void setLocation(Point origin)
public void setBounds(Rectangle r) // JDK 1.6

// The associated get methods (in java.awt.Component) are:


public int getWidth()
public int getHeight()
public int getX()
public int getY()
public Dimension getSize()
public Point getLocation()
public Rectangle getBounds()
// No setX(), setY(), setWidth(), setHeight()

You can get the screen size via static method Toolkit.getDefaultToolkit().getScreenSize() . For example,


Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); // Get the screen dimension
int screenWidth = dim.width;
int screenHeight = dim.heigth;

You can also run your application in full-screen mode (with or without decorations such as title bar), instead of
window-mode. Read "Swing How-To".
A quick way to center your application on the screen is to use setLocationRelativeTo(null):
setSize(WINDOW_WIDTH, WINDOW_HEIGHT); // or pack() the components
setLocationRelativeTo(null); // center the window on the screen
// shall be run after setSize()
setVisible(true); // show it

1.5  Text Components: JTextField, JTextArea, JEditorPane

Gangadri K Page 72
Core Java 73

Swing provides 6 text components, as shown in the above class diagram. All text components extends
from JTextComponent.
1. JTextField, JPasswordField, JFormattedTextField: For displaying only one line of editable text. Like
buttons, they triggerActionEvent when user hits the "enter" key.
2. JTextArea: Plain text area for displaying multiple lines of editable text, unformatted. All the texts are in the
same font.
3. JEditorPane, JTextPane: A styled text area which can use more than one font. They support embedded
images and embedded components. JEditorPane can load HMTL-formatted text from a URL.
Example: JTextField, JPasswordField, JFormattedTextField, and JTextArea

Gangadri K Page 73
Core Java 74

This example illustrates single-line JTextField, JPasswordField, JFormattedField, and multi-


line JTextArea wrapped inside an JScrollPane.
1import java.awt.*;
2import java.awt.event.*;
3import javax.swing.*;
4
5/** Test JTextField, JPasswordField, JFormattedTextField, JTextArea */
6@SuppressWarnings("serial")
7public class JTextComponentDemo extends JFrame {
8
9 // Private variables of the GUI components
10 JTextField tField;
11 JPasswordField pwField;
12 JTextArea tArea;
13 JFormattedTextField formattedField;
14
15 /** Constructor to set up all the GUI components */
16 public JTextComponentDemo() {
17 // JPanel for the text fields
18 JPanel tfPanel = new JPanel(new GridLayout(3, 2, 10, 2));
19 tfPanel.setBorder(BorderFactory.createTitledBorder("Text Fields: "));
20
21 // Regular text field (Row 1)
22 tfPanel.add(new JLabel(" JTextField: "));
23 tField = new JTextField(10);
24 tfPanel.add(tField);
25 tField.addActionListener(new ActionListener() {
26 @Override
27 public void actionPerformed(ActionEvent e) {
28 tArea.append("\nYou have typed " + tField.getText());
29 }
30 });
31
32 // Password field (Row 2)
33 tfPanel.add(new JLabel(" JPasswordField: "));
34 pwField = new JPasswordField(10);
35 tfPanel.add(pwField);
36 pwField.addActionListener(new ActionListener() {
37 @Override
38 public void actionPerformed(ActionEvent e) {
39 tArea.append("\nYou password is " + new String(pwField.getPassword()));
40 }
41 });
42
43 // Formatted text field (Row 3)
44 tfPanel.add(new JLabel(" JFormattedTextField"));
45 formattedField = new JFormattedTextField(java.util.Calendar
46 .getInstance().getTime());
47 tfPanel.add(formattedField);
48
49 // Create a JTextArea
50 tArea = new JTextArea("A JTextArea is a \"plain\" editable text component, "
51 + "which means that although it can display text "
52 + "in any font, all of the text is in the same font.");
53 tArea.setFont(new Font("Serif", Font.ITALIC, 13));
54 tArea.setLineWrap(true); // wrap line
55 tArea.setWrapStyleWord(true); // wrap line at word boundary

Gangadri K Page 74
Core Java 75

56 tArea.setBackground(new Color(204, 238, 241)); // light blue


57 // Wrap the JTextArea inside a JScrollPane
58 JScrollPane tAreaScrollPane = new JScrollPane(tArea);
59 tAreaScrollPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
60 tAreaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
61
62 // Setup the content-pane of JFrame in BorderLayout
63 Container cp = this.getContentPane();
64 cp.setLayout(new BorderLayout(5, 5));
65 cp.add(tfPanel, BorderLayout.NORTH);
66 cp.add(tAreaScrollPane, BorderLayout.CENTER);
67
68 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
69 setTitle("JTextComponent Demo");
70 setSize(350, 350);
71 setVisible(true);
72 }
73
74 /** The entry main() method */
75 public static void main(String[] args) {
76 // Run GUI codes in Event-Dispatching thread for thread safety
77 SwingUtilities.invokeLater(new Runnable() {
78 @Override
79 public void run() {
80 new JTextComponentDemo(); // Let the constructor do the job
81 }
82 });
83 }
84}
JPasswordField
Use getPassword() to get the password entered in a char[]. [TODO: Security Issues]
JFormattedTextField (Advanced)

[TODO]
JTextArea wrapped in a JScrollPane
It is common to wrap a JTextArea inside a JScrollPane, so as to scroll the text area (horizontally or vertically). To
do so, allocate a JScrollPane with the JTextArea as the argument.
JTextArea tArea = new JTextArea(...); // Allocate JTextArea
JScrollPane tAreaScrollPane = new JScrollPane(tArea); // Allocate JScrollPane which wraps the
JTextArea
tAreaScrollPane.setVerticalScrollBarPolicy(...); // Configure vertical scroll bar
tAreaScrollPane.setHorizontalScrollBarPolicy(...); // Configure horizontal scroll bar

JTextArea's Properties

You can replace the document, or append or insert more text.

public void append(String str)


// Append the str to the end of the document
public void replaceRange(String str, int startPos, int endPos)
// Replace with the str from startPos to endPos position
public void insert(String str, int pos)
// Insert the str after the specified position

JEditorPane as HTML Browser


You can use JEditorPane to display an HTML document (but no CSS and JavaScript). Again, it is common to wrap
a JEditorPane inside aJScrollPane. For example,

Gangadri K Page 75
Core Java 76

JEditorPane editorPane = new JEditorPane(); // allocate a JEditorPane


editorPane.setEditable(false);
try {
// Form a URL and display the HTML page on the editor-pane
URL url = new URL("http://www3.ntu.edu.sg/home/ehchua/programming/index.html");
editorPane.setPage(url);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// Wrap the JEditorPane inside a JScrollPane
JScrollPane editorScrollPane = new JScrollPane(editorPane);
editorScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setContentPane(editorScrollPane);

JTextPane (Advanced)
JTextPane is used for formatted styled text display; whereas JTextArea is used for plain text display. Although you
can set the font and style forJTextArea, all the text is display in the same font. In JTextPane, you can set different
fonts and styles for different sections of text.
You can use JTextPane for to develop an editor (such as NotePad or NotePad++) with different sections of text
displayed in different fonts and colors.
Example: See Swing Tutorial's "Text Component Features". This is an excellent example that illustrates many
features and concepts.
Text Component API: It provides many features, from cut and paste to changing the selected text. See Swing
Tutorial's "Text Component API".
1.6  Buttons and
ComboBox: JButton, JCheckBox, JRadioButton, JComboBox

Gangadri K Page 76
Core Java 77

Read: Swing Tutorial's "How to Use Buttons, Check Boxes, and Radio Buttons".
A user can click a button (or a menu item) to trigger a specific action. Swing supports mouse-less operations,
where user could use a keyboard short-cut (called mnemonic) to activate the action.
Buttons and menu-items are inherited from AbstractButton, as shown in the class diagram.
You could place a text string (called button's label) as well as an icon on the button. You could use different icons
for different button
states: defaultIcon,disabledIcon, pressedIcon, selectedIcon, rolloverIcon,disabledSelectedIcon, rollover
SelectedIcon. The defaultIcon can be set via the constructor or setIcon() method. The other icons can be set
via setXxxIcon() methods. You can set the alignment of text and button
viasetHorizontalAlignment() and setVerticalAlignment() methods. You can set the position of the text
relative to the icon viasetHorizontalTextPosition() and setVerticalTextPosition().

Swing supports many type of buttons.


Command Buttons: JButton
Click to fires an ActionEvent to all its registered ActionListeners.
Toggle Buttons: JRadioButton, JCheckBox, JToggleButton
Toggle buttons are two-state buttons: SELECTED or DESELECTED.
For radio button, you can choose none or one among the group. JRadioButtons are typically added into
a ButtonGroup to ensure exclusive selection.JRadioButton fires ItemEvent to its ItemListeners. It also
fires ActionEvent to its ActionListeners. Both ItemEvent and ActionEvent can be used.
For checkboxes, you can choose none or more among the group. JCheckBoxes fire ItemEvent as well
as ActionEvent. We typically use ItemEventas we may need to distinguish between item-states
of SELECTED and DESELECTED.
The ItemListner (of ItemEvent) declares one abstract method itemStateChanged(ItemEvent e).
JComboBox
JComboBox can be used to provide a drop-down menu. It supports single-selection and multiple-
selection. JComboBox receives a Object array (typically a String array), which provides the items in the drop-down
list. JComboBox fires ItemEvent. We could use JComboBox'sgetSelectedIndex() to get the index of the selected
item; or getSelectedItem() to get the selected Object. JComboBox also fires ActionEvent.
Example on JButton, JRadioButton and JComboBox

In this example, we shall modify our counter application to include two radio buttons for specifying counting
up/down, and a combo-box to select the count-step size.

1import java.awt.*;
2import java.awt.event.*;
3import javax.swing.*;
4
5/** Counter with JRadioButton and JComboBox */
6@SuppressWarnings("serial")
7public class SwingCounterRadioCombo extends JFrame {
8 private JTextField tfCount;
9 private int count = 0; // counter's value
10 private boolean countingUp = true; // counting up or down
11 private int step = 1; // increment step size
12
13 /** Constructor to setup the UI */
14 public SwingCounterRadioCombo () {

Gangadri K Page 77
Core Java 78

15 Container cp = getContentPane();
16 cp.setLayout(new FlowLayout());
17
18 // Create JLabel and JTextField
19 cp.add(new JLabel("Counter:"));
20 tfCount = new JTextField("0", 5);
21 tfCount.setEditable(false);
22 tfCount.setHorizontalAlignment(JTextField.RIGHT);
23 cp.add(tfCount);
24
25 // Create JRadioButton for counting up and down
26 JRadioButton rbUp = new JRadioButton("Up", true);
27 rbUp.setMnemonic(KeyEvent.VK_U);
28 cp.add(rbUp);
29 rbUp.addActionListener(new ActionListener() {
30 @Override
31 public void actionPerformed(ActionEvent e) {
32 countingUp = true;
33 }
34 });
35 JRadioButton rbDown = new JRadioButton("Down", true);
36 rbDown.setMnemonic(KeyEvent.VK_D);
37 cp.add(rbDown);
38 rbDown.addActionListener(new ActionListener() {
39 @Override
40 public void actionPerformed(ActionEvent e) {
41 countingUp = false;
42 }
43 });
44 // Setup a ButtonGroup to ensure exclusive selection
45 ButtonGroup btnGp = new ButtonGroup();
46 btnGp.add(rbUp);
47 btnGp.add(rbDown);
48
49 // Create JComboBox for setting the count step size
50 add(new JLabel("Step:"));
51 final Integer[] steps = {1, 2, 3, 4, 5}; // auto-upcast
52 final JComboBox<Integer> comboCount = new JComboBox<Integer>(steps);
53 comboCount.setPreferredSize(new Dimension(60, 20));
54 cp.add(comboCount);
55 comboCount.addItemListener(new ItemListener() {
56 @Override
57 public void itemStateChanged(ItemEvent e) {
58 if (e.getStateChange() == ItemEvent.SELECTED) {
59 step = (Integer)comboCount.getSelectedItem();
60 }
61 }
62 });
63
64 // Create JButton for "Count"
65 JButton btnCount = new JButton("Count");
66 btnCount.setMnemonic(KeyEvent.VK_C);
67 cp.add(btnCount);
68 btnCount.addActionListener(new ActionListener() {
69 @Override
70 public void actionPerformed(ActionEvent e) {
71 if (countingUp) {
72 count += step;

Gangadri K Page 78
Core Java 79

73 } else {
74 count -= step;
75 }
76 tfCount.setText(count + "");
77 }
78 });
79
80 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
81 setTitle("Swing Counter with RadioButton & ComboBox");
82 setSize(480, 100);
83 setVisible(true);
84 }
85
86 /** The entry main() method */
87 public static void main(String[] args) {
88 // Run the GUI codes in the Event-Dispatching thread for thread-safety
89 SwingUtilities.invokeLater(new Runnable() {
90 @Override
91 public void run() {
92 new SwingCounterRadioCombo(); // Let the constructor do the job
93 }
94 });
95 }
96}

Example on JRadioButton, JCheckBox and JComboBox

In this example, we have two groups of radio buttons: one group to set the horizontal alignment of the  JLabel,
and processed via ItemEvent; another group sets the vertical alignment and processed via ActionEvent.
1import java.awt.*;
2import java.awt.event.*;
3import java.net.URL;
4import javax.swing.*;
5
6/** Test JRadioButton, JCheckBox and JComboBox */
7@SuppressWarnings("serial")
8public class ButtonComboBoxDemo extends JFrame {
9 // private variables of GUI components
10 private JLabel lblForTest;
11 private String imgCrossFilename = "images/cross.gif";
12 private String lblText = "Cross";
13 private Icon iconCross;
14

Gangadri K Page 79
Core Java 80

15 private JRadioButton rbLeft, rbCenter, rbRight, rbTop, rbMiddle, rbBottom;


16 private JCheckBox cbText, cbIcon;
17 private JComboBox<String> comboColor;
18
19 /** Constructor to setup the UI components */
20 public ButtonComboBoxDemo() {
21 // Create a JLabel with text and icon for manipulation
22 URL imgURL = getClass().getClassLoader().getResource(imgCrossFilename);
23 if (imgURL != null) {
24 iconCross = new ImageIcon(imgURL);
25 } else {
26 System.err.println("Couldn't find file: " + imgCrossFilename);
27 }
28 lblForTest = new JLabel(lblText, iconCross, SwingConstants.CENTER);
29 lblForTest.setOpaque(true);
30 lblForTest.setBackground(new Color(204, 238, 241));
31 lblForTest.setForeground(Color.RED);
32 lblForTest.setFont(new Font(Font.SANS_SERIF, Font.ITALIC, 18));
33
34 // Create radio buttons for setting horizontal alignment of the JLabel
35 rbLeft = new JRadioButton("Left");
36 rbLeft.setMnemonic(KeyEvent.VK_L);
37 rbCenter = new JRadioButton("Center", true); // selected
38 rbCenter.setMnemonic(KeyEvent.VK_C);
39 rbRight = new JRadioButton("Right");
40 rbRight.setMnemonic(KeyEvent.VK_R);
41 // Put the radio buttons into a ButtonGroup to ensure exclusive selection
42 ButtonGroup btnGroupH = new ButtonGroup();
43 btnGroupH.add(rbLeft);
44 btnGroupH.add(rbRight);
45 btnGroupH.add(rbCenter);
46 // Set up a JPanel to hold all radio buttons
47 JPanel pnlRbtnH = new JPanel(new GridLayout(1, 0)); // single row
48 pnlRbtnH.add(rbLeft);
49 pnlRbtnH.add(rbCenter);
50 pnlRbtnH.add(rbRight);
51 pnlRbtnH.setBorder(BorderFactory.createTitledBorder("Horizontal Alignment"));
52
53 // A ItemListener for all Radio buttons
54 ItemListener listener = new ItemListener() {
55 @Override
56 public void itemStateChanged(ItemEvent e) {
57 if (e.getStateChange() == ItemEvent.SELECTED) {
58 if (e.getSource() == rbLeft) {
59 lblForTest.setHorizontalAlignment(SwingConstants.LEFT);
60 } else if (e.getSource() == rbCenter) {
61 lblForTest.setHorizontalAlignment(SwingConstants.CENTER);
62 } else if (e.getSource() == rbRight) {
63 lblForTest.setHorizontalAlignment(SwingConstants.RIGHT);
64 }
65 }
66 }
67 };
68 rbLeft.addItemListener(listener);
69 rbCenter.addItemListener(listener);
70 rbRight.addItemListener(listener);
71
72 // Create radio buttons for setting vertical alignment of the JLabel

Gangadri K Page 80
Core Java 81

73 rbTop = new JRadioButton("Top");


74 rbTop.setMnemonic(KeyEvent.VK_T);
75 rbMiddle = new JRadioButton("Middle", true); // selected
76 rbMiddle.setMnemonic(KeyEvent.VK_M);
77 rbBottom = new JRadioButton("Bottom");
78 rbBottom.setMnemonic(KeyEvent.VK_B);
79 // Put the radio buttons into a ButtonGroup to ensure exclusive selection
80 ButtonGroup btnGroupV = new ButtonGroup();
81 btnGroupV.add(rbTop);
82 btnGroupV.add(rbMiddle);
83 btnGroupV.add(rbBottom);
84 // Set up a JPanel to hold all radio buttons
85 JPanel pnlRbtnV = new JPanel(new GridLayout(1, 0)); // single row
86 pnlRbtnV.add(rbTop);
87 pnlRbtnV.add(rbMiddle);
88 pnlRbtnV.add(rbBottom);
89 pnlRbtnV.setBorder(BorderFactory.createTitledBorder("Vertical Alignment"));
90
91 // Radio buttons also fire ActionEvent
92 rbTop.addActionListener(new ActionListener() {
93 @Override
94 public void actionPerformed(ActionEvent e) {
95 lblForTest.setVerticalAlignment(SwingConstants.TOP);
96 }
97 });
98 rbMiddle.addActionListener(new ActionListener() {
99 @Override
100 public void actionPerformed(ActionEvent e) {
101 lblForTest.setVerticalAlignment(SwingConstants.CENTER);
102 }
103 });
104 rbBottom.addActionListener(new ActionListener() {
105 @Override
106 public void actionPerformed(ActionEvent e) {
107 lblForTest.setVerticalAlignment(SwingConstants.BOTTOM);
108 }
109 });
110
111 // Create checkboxes for selecting text, icon, or both, or none
112 cbText = new JCheckBox("Text", true); // selected
113 cbText.setMnemonic(KeyEvent.VK_T);
114 cbIcon = new JCheckBox("Icon", true); // selected
115 cbIcon.setMnemonic(KeyEvent.VK_I);
116 cbIcon.setSelected(true);
117 // Set up a JPanel to hold all checkboxes
118 JPanel pnlCbox = new JPanel(new GridLayout(0, 1)); // single column
119 pnlCbox.add(cbText);
120 pnlCbox.add(cbIcon);
121 // Checkboxes fire ItemEvent. Use an anonymous inner class as ItemListener
122 cbText.addItemListener(new ItemListener() {
123 @Override
124 public void itemStateChanged(ItemEvent e) {
125 // Need to handle both SELECTED and DESELECTED
126 if (e.getStateChange() == ItemEvent.SELECTED) {
127 lblForTest.setText(lblText);
128 } else {
129 lblForTest.setText("");
130 }

Gangadri K Page 81
Core Java 82

131 }
132 });
133 cbIcon.addItemListener(new ItemListener() {
134 @Override
135 public void itemStateChanged(ItemEvent e) {
136 // Need to handle both SELECTED and DESELECTED
137 if (e.getStateChange() == ItemEvent.SELECTED) {
138 lblForTest.setIcon(iconCross);
139 } else {
140 lblForTest.setIcon(null);
141 }
142 }
143 });
144
145 // Create combobox (drop-down menu) for the foreground color of the JLabel
146 String[] strColors = {"Red", "Blue", "Green",
147 "Cyan", "Magenta", "Yellow", "Black"};
148 final Color[] colors = {Color.RED, Color.BLUE, Color.GREEN,
149 Color.CYAN, Color.MAGENTA, Color.YELLOW, Color.BLACK};
150 comboColor = new JComboBox<String>(strColors);
151 comboColor.addItemListener(new ItemListener() {
152 @Override
153 public void itemStateChanged(ItemEvent e) {
154 if (e.getStateChange() == ItemEvent.SELECTED) {
155 lblForTest.setForeground(colors[comboColor.getSelectedIndex()]);
156 }
157 }
158 });
159 // Set up a JPanel for the combobox
160 JPanel pnlCombo = new JPanel(new FlowLayout());
161 pnlCombo.add(comboColor);
162
163 // Set up the content-pane with BorderLayout and adds the panels
164 Container cp = this.getContentPane();
165 cp.setLayout(new BorderLayout());
166 cp.add(lblForTest, BorderLayout.CENTER);
167 cp.add(pnlRbtnH, BorderLayout.NORTH);
168 cp.add(pnlRbtnV, BorderLayout.SOUTH);
169 cp.add(pnlCbox, BorderLayout.WEST);
170 cp.add(pnlCombo, BorderLayout.EAST);
171
172 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
173 setTitle("Button and ComboBox Demo");
174 setSize(400, 300); // or pack() the components
175 setLocationRelativeTo(null);
176 setVisible(true);
177 }
178
179 /** The entry main() method */
180 public static void main(String[] args) {
181 // Run GUI codes in the Event-Dispatching thread for thread safety
182 SwingUtilities.invokeLater(new Runnable() {
183 public void run() {
184 new ButtonComboBoxDemo(); // Let the constructor do the job
185 }
186 });
187 }
188}

Gangadri K Page 82
Core Java 83

1.7  Menu-Bar: JMenuBar, JMenu, JMenuItem

The menu-bar is at the same level as the content-pane (of the top-level container JFrame). It is set via
the JFrame's setJMenuBar() method (similar to setContentPane()).
To create a menu-bar, construct a JMenuBar. A menu-bar (JMenuBar) contains menu (JMenu). A menu contains
menu-item (JMenuItem).JMenuItem is a subclass of AbstractButton, similar
to JButton.JMenuItem fires ActionEvent upon activation to all its registeredActionListener.
Example

This menu-bar contains 2 menus (Menu-A and Menu-B). Menu-A contains 2 menu-items (Up and Down). Menu-B
has 1 menu-item (Reset).

1import java.awt.*;
2import java.awt.event.*;
3import javax.swing.*;
4
5/** Testing menu-bar of JFrame */
6public class TestJMenuBar extends JFrame {
7
8 JTextField display;
9 int count = 0;
10
11 /** Constructor to setup the GUI */
12 public TestJMenuBar() {
13 // A menu-bar contains menus. A menu contains menu-items (or sub-Menu)

Gangadri K Page 83
Core Java 84

14 JMenuBar menuBar; // the menu-bar


15 JMenu menu; // each menu in the menu-bar
16 JMenuItem menuItem; // an item in a menu
17
18 menuBar = new JMenuBar();
19
20 // First Menu
21 menu = new JMenu("Menu-A");
22 menu.setMnemonic(KeyEvent.VK_A); // alt short-cut key
23 menuBar.add(menu); // the menu-bar adds this menu
24
25 menuItem = new JMenuItem("Up", KeyEvent.VK_U);
26 menu.add(menuItem); // the menu adds this item
27 menuItem.addActionListener(new ActionListener() {
28 @Override
29 public void actionPerformed(ActionEvent e) {
30 ++count;
31 display.setText(count + "");
32 }
33 });
34
35 menuItem = new JMenuItem("Down", KeyEvent.VK_D);
36 menu.add(menuItem); // the menu adds this item
37 menuItem.addActionListener(new ActionListener() {
38 @Override
39 public void actionPerformed(ActionEvent e) {
40 --count;
41 display.setText(count + "");
42 }
43 });
44
45 // Second Menu
46 menu = new JMenu("Menu-B");
47 menu.setMnemonic(KeyEvent.VK_B); // short-cut key
48 menuBar.add(menu); // the menu bar adds this menu
49
50 menuItem = new JMenuItem("Reset", KeyEvent.VK_R);
51 menu.add(menuItem); // the menu adds this item
52 menuItem.addActionListener(new ActionListener() {
53 @Override
54 public void actionPerformed(ActionEvent e) {
55 count = 0;
56 display.setText(count + "");
57 }
58 });
59
60 setJMenuBar(menuBar); // "this" JFrame sets its menu-bar
61
62 Container cp = getContentPane();
63 cp.setLayout(new FlowLayout());
64 display = new JTextField("0", 10);
65 cp.add(display);
66
67 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
68 setTitle("Test MenuBar");
69 setSize(300, 100);
70 setVisible(true);
71 }

Gangadri K Page 84
Core Java 85

72
73 /** The entry main() method */
74 public static void main(String[] args) {
75 // Run the GUI codes on the event-dispatching thread for thread safety
76 SwingUtilities.invokeLater(new Runnable() {
77 @Override
78 public void run() {
79 new TestJMenuBar(); // Let the constructor do the job
80 }
81 });
82 }
83}

1.8  JOptionPane: Interacting with the User


The javax.swing.JOptionPane provides standard pre-built diglog boxes to interact with user for both input and
output. To create a dialog box, use one of the static methods JOptionPane.showXxxDialog().
// Prompt for user input
public static String showInputDialog(Object message, [Object initialSelectionValue])
public static Object showInputDialog(Component parentComponent, Object message,
[String title], [int messageType], [Icon icon], [Object[] options], [Object initialValue])

// Asks a confirming question (yes/no/cancel)


public static int showConfirmDialog(Component parentComponent, Object message,
[String title], [int optionType], [int messageType], [Icon icon])

// Display a message
public static void showMessageDialog(Component parentComponent, Object message,
[String title], [int messageType], [Icon icon])

// Support all features of the above three methods


public static int showOptionDialog(Component parentComponent, Object message,
String title, int optionType, int messageType, Icon icon, Object[] options, Object
initialValue)

// Component parentComponent: parent of this dialog box, for poisitioning.


// If null, centered on the screen.
// Object message: the message, typically a String.
// String title: the title for the dialog box
// int messageType: the style of the message,
// JOptionPane.ERROR_MESSAGE, INFORMATION_MESSAGE, WARNING_MESSAGE, QUESTION_MESSAGE,
PLAIN_MESSAGE.
// int optionType: the set of option buttons,
// JOptionPane.DEFAULT_OPTION, YES_NO_OPTION, YES_NO_CANCEL_OPTION, OK_CANCEL_OPTION
// Icon icon: a decorative icon, default depends on the messageType
// Object[] options, Object initialValue:

All these methods block the caller until the user's interaction is complete. Each of these methods also comes has
a showInternalXxxDialog() version, which uses an internal frame to hold the dialog box.
Example: Input, Confirm and Message Dialogs
1import javax.swing.*;
2public class JOptionPaneTest {
3 public static void main(String[] args) {
4 // JOptionPane does not have to run under a Swing Application (extends JFrame).
5 // It can run directly under main().
6 String inStr = JOptionPane.showInputDialog(null, "Ask for user input (returns a String)",
7 "Input Dialog", JOptionPane.PLAIN_MESSAGE);

Gangadri K Page 85
Core Java 86

8 System.out.println("You have entered " + inStr);


9 JOptionPane.showMessageDialog(null, "Display a message (returns void)!",
10 "Message Dialog", JOptionPane.PLAIN_MESSAGE);
11 int answer = JOptionPane.showConfirmDialog(null, "Ask for confirmation (returns an int)",
12 "Confirm Dialog", JOptionPane.YES_NO_CANCEL_OPTION);
13 switch (answer) {
14 case JOptionPane.YES_OPTION:
15 System.out.println("You clicked YES"); break;
16 case JOptionPane.NO_OPTION:
17 System.out.println("You clicked NO"); break;
18 case JOptionPane.CANCEL_OPTION:
19 System.out.println("You clicked Cancel"); break;
20 }
21 }
22}

   

Take note that input dialog returns the String entered by the user; confirm dialog returns an int


(JOptionPane.YES_OPTION, NO_OPTION,CANCEL_OPTION); message dialog returns void. Furthermore, you can
use JOptionPane directly under main() to prompt user for input, similar to text-based input via Scanner.
Example: Prompting User for Input with Validation

1import java.awt.*;
2import java.awt.event.*;
3import javax.swing.*;
4
5public class InputDialogWithValidation extends JFrame {
6 JTextField tfDisplay; // to display the number entered

Gangadri K Page 86
Core Java 87

7
8 /** Constructor to setup the GUI components */
9 public InputDialogWithValidation() {
10 Container cp = getContentPane();
11 cp.setLayout(new FlowLayout());
12
13 tfDisplay = new JTextField(10);
14 tfDisplay.setEditable(false);
15 cp.add(tfDisplay);
16
17 JButton btn = new JButton("Input");
18 cp.add(btn);
19 btn.addActionListener(new ActionListener() {
20 @Override
21 public void actionPerformed(ActionEvent e) {
22 boolean validInput = false; // for input validation
23 int numberIn;
24 String inputStr = JOptionPane.showInputDialog("Enter a number [1-9]: ");
25 do {
26 try {
27 numberIn = Integer.parseInt(inputStr);
28 } catch (NumberFormatException ex) {
29 numberIn = -1; // input triggered NumberFormatException, set to invalid
30 }
31 if (numberIn < 1 || numberIn > 9) {
32 inputStr = JOptionPane.showInputDialog("Invalid numner! Enter a number [1-9]: ");
33 } else {
34 JOptionPane.showMessageDialog(null, "You have entered " + numberIn);
35 validInput = true;
36 }
37 } while (!validInput); // repeat if input is not valid
38 tfDisplay.setText(numberIn + "");
39 }
40 });
41 setDefaultCloseOperation(EXIT_ON_CLOSE);
42 setSize(300, 100);
43 setTitle("Test Input Dialog");
44 setVisible(true);
45 }
46
47 /** The "main" entry method */
48 public static void main(String[] args) {
49 // Run the GUI code on the Event-Dispatching Thread for thread safety
50 javax.swing.SwingUtilities.invokeLater(new Runnable() {
51 public void run() {
52 new InputDialogWithValidation(); // Let the constructor do the job
53 }
54 });
55 }
56}

2.  Pluggable Look and Feel


Swing supports the so-called "pluggable look and feel (plaf)" for its JComponents. The "look" refers to the
appearance of the widgets ( JComponent); while the "feel" refers to how the widgets behave (e.g., the behaviors of
mouse-click for the various mouse-buttons). "Pluggable" refers the ability of changing the look and feel at runtime.

Gangadri K Page 87
Core Java 88

You can choose to use the default Java look and feel, the native system's look and feel (Windows, Linux, Mac), or
the newer cross-platform Nimbus look and feel.
Pluggable look and feel is supported in Swing's components by separating the components into two
classes: JComponent (in package javax.swing) and ComponetUI (in package javax.swing.plaf). The ComponetUI,
called UI delegate, handles all aspects relating to look and feel. Nonetheless, you shall not interact with the UI
delegate directly.
These look and feel are supported (in packages javax.swing.plaf and javax.swing.plaf.*):
1. Java Look and Feel: Also called CrossPlatformLookAndFeel, or Metal L&F. The default L&F which provides
the same look and feel across all the platforms.
2. System Look and Feel: the L&F of the native system (e.g., Windows, Linux, Mac).
3. Nimbus Look and Feel: the newer cross-platform look and feel released in JDK 1.6 update 10.

The JFC demos (included in JDK demo) "SwingSet2" and "SwingSet3" show the various L&Fs.

2.1  Setting the Look and Feel


You need to set the Look and Feel as the first step in your GUI construction. There are a few ways to set the Look
and Feel.
Via UIManager.setLookAndFeel()
You can use the static method UIManager.setLookAndFeel(String className) to set the look and feel.
 You can either use
the static method UIManager.getCrossPlatformLookAndFeelClassName() ,UIManager.getSystemLookAndF
eelClassName() to get the classname string for Java F&F and Native System L&F; or
 Use the actual classname string such as " javax.swing.plaf.metal.MetalLookAndFeel " (for Java L&F),
"com.sun.java.swing.plaf.windows.WindowsLookAndFeel " (Windows L&F),
"javax.swing.plaf.nimbus.NimbusLookAndFeel " (Nimbus L&F) and
"com.sun.java.swing.plaf.motif.MotifLookAndFeel " (Motif L&F).

For example,

Gangadri K Page 88
Core Java 89

// Set the UI manager (shall be the first step of the GUI construction)
try {
// Set to cross-platform Java Look and Feel (also called "Metal")
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}

The alternative Look and Feel (under Windows System) are:

// Native System Look and Feel


UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

// Cross-platform Java Look and Feel (also called "Metal")


UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");

// Windows Look and Feel


UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");

// Cross-platform Nimbus Look and Feel (JDK 1.6u10)


UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");

// Windows Classic Look and Feel


UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");

// CDE/Motif Look and Feel


UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");

You can use static method UIManager.getInstalledLookAndFeels()  to list all the installed L&F:

UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels();


for (UIManager.LookAndFeelInfo laf : lafs) {
System.out.println(laf);
}
javax.swing.UIManager$LookAndFeelInfo[Metal javax.swing.plaf.metal.MetalLookAndFeel]
javax.swing.UIManager$LookAndFeelInfo[Nimbus javax.swing.plaf.nimbus.NimbusLookAndFeel]
javax.swing.UIManager$LookAndFeelInfo[CDE/Motif com.sun.java.swing.plaf.motif.MotifLookAndFeel]
javax.swing.UIManager$LookAndFeelInfo[Windows
com.sun.java.swing.plaf.windows.WindowsLookAndFeel]
javax.swing.UIManager$LookAndFeelInfo[Windows Classic
com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel]

Via the Command Line Option "swing.defaultlaf"

For example,

// Set to Nimbus L&F


java -Dswing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel MySwingApp
// Set to Windows L&F

Gangadri K Page 89
Core Java 90

java -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel MySwingApp

Via the "swing.properties" file


Create a "swing.properties" file (placed under "$JAVA_HOME/lib" directory) with a option "swing.defaultlaf":
# Swing Look and Feel
swing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel

2.2  Nimbus Look and Feel (JDK 1.6u10)


Reference:  Swing Tutorial's "Nimbus Look and Feel"
@ http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/nimbus.html.
Nimbus is a polished cross-platform look and feel introduced in the JDK 1.6 Update 10. The JFC demo "SwingSet3"
(under the JDK demo) shows the Nimbus look and feel for the various Swing JComponents. "Nimbus uses Java 2D
vector graphics to draw the user interface (UI), rather than static bitmaps, so the UI can be crisply rendered at any
resolution. Nimbus is highly customizable. You can use the Nimbus look and feel as is, or you can skin (customize)
the look with your own brand."

To enable Nimbus L&F:


1. Use UIManager.setLookAndFeel():

2. try {
3. // Set to cross-platform Nimbus Look and Feel
4. UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel"); // JDK 1.7
5. } catch (Exception e) {
6. e.printStackTrace();
7. }
8.
9. // OR more robust codes
10. try {
11. // Check if Nimbus is supported and get its classname
12. for (UIManager.LookAndFeelInfo lafInfo : UIManager.getInstalledLookAndFeels()) {
13. if ("Nimbus".equals(lafInfo.getName())) {
14. UIManager.setLookAndFeel(lafInfo.getClassName());
15. break;
16. }
17. }
18. } catch (Exception e) {
19. try {
20. // If Nimbus is not available, set to the default Java (metal) look and feel
21. UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
22. } catch (Exception e1) {
23. e1.printStackTrace();
24. }

Take note that the Nmibus package in JDK 1.6u10 is


"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel "; while in JDK 1.7, it is called
"javax.swing.plaf.nimbus.NimbusLookAndFeel ".
25. Use command-line option "swing.defaultlaf":

java -Dswing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel MySwingApp

26. Use a "swing.properties" file (under the "$JAVA_HOME/lib"):


27. # Set to Nimbus Look and Feel (System-wide)

Gangadri K Page 90
Core Java 91

swing.defaultlaf=javax.swing.plaf.nimbus.NimbusLookAndFeel

A Nimbus component can have 4 different sizes: large, regular, small and mini. You can choose the size via:

myButton.putClientProperty("JComponent.sizeVariant", "mini");
// default is "regular", options are "large", "small" and "mini"

You can change the color theme via:

UIManager.put("nimbusBase", new Color(...)); // Base color


UIManager.put("nimbusBlueGrey", new Color(...)); // BlueGrey
UIManager.put("control", new Color(...)); // Control

// Set to Nimbus L&F


for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels() {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
......

You can customize the look and feel, which is beyond the scope of this article.

3.  More on Layout Manager


Reference:  Swing Tutorial's "Laying Out Components Within a Container"
@ http://docs.oracle.com/javase/tutorial/uiswing/layout/index.html.
3.1  Key Points on Layout Manager
Layout in Production
Use NetBeans' visual GroupLayout to layout the components in production; or GridBagLayout if you prefer to
code yourself (why?). The rest ofLayoutManagers (such as FlowLayout, BorderLayout, GridLayout) are meant for
prototyping.
The two components you need to worry about layout are JPanel and the content-pane of the top-level containers
(such as JFrame, JApplet andJDialog).
 JPanel defaults to FlowLayout (with alignment of CENTER, hgap and vgap of 5 pixels); or you can set the
layout of a JPanel in its constructor.
 All content-panes default to BorderLayout (with hgap and vgap of 0). In BorderLayout,
the add(aComponent) without specifying the zone adds the component to the CENTER. Second add() will
override the first add().
Absolute Positioning without LayoutManager shall be avoided, as it does not adjust well on screens with different
resolutions; or when the window is resize.
Hints on sizes and alignments
You can provide hints on the minimum, preferred and maximum sizes of a component
via setMinimumSize(), setPreferredSize() andsetMaximumSize() methods. However, some layout managers
ignore these requests, especially the maximum size. You can also do these by extending a subclass and overriding
the getXxxSize() call-back methods.
The setSize() method must be issued at the correct point, or else it will not work (as it was overridden by another
implicit setSize()). [TODO: Check]
Similarly, you can provide hints on horizontal and vertical alignments (of the edges) among components
via setAlignmentX() and setAlignmentY()methods. BoxLayout honors them but other layout managers may
ignore these hints. You can also extend a subclass and override the getAlignmentX() and getAlignmentY() call-
back methods.
Gangadri K Page 91
Core Java 92

[TODO] setSize(), pack(), validate() and invalidate() for Container, revalidate() and repaint() for Comp
onent, doLayout().
3.2  Methods validate() and doLayout()
If you change a property of a LayoutManager, such as hgap or vgap of GridLayout, you need to issue
a doLayout() to force the LayoutManagerto re-layout the components using the new property.
A container has only one LayoutManager. Nonetheless, you can change
the LayoutManager via setLayout(newLayoutManager). You need to follow with a validate() to ask the
container to re-layout the components.
Code Example
This example creates 6 buttons, which are arranged in 3x2 and 2x3 GridLayout alternately upon clicking any
button.
1import java.awt.*;
2import java.awt.event.*;
3import javax.swing.*;
4
5/** Changing the LayoutManager of the Container
6 between 3*2 GridLayout and 2*3 GridLayout */
7@SuppressWarnings("serial")
8public class SetLayoutTest extends JFrame {
9 private int rows = 3;
10 private int cols = 2;
11 private Container cp; // content-pane of JFrame
12
13 /** Constructor to setup the UI components */
14 public SetLayoutTest() {
15 cp = this.getContentPane();
16 cp.setLayout(new GridLayout(rows, cols, 3, 3));
17
18 // Create an instance of ActionListener to listen to all Buttons
19 ButtonsListener listener = new ButtonsListener();
20
21 // Create rows*cols Buttons and add to content-pane
22 JButton[] buttons = new JButton[rows * cols];
23 for (int i = 0; i < buttons.length; ++i) {
24 buttons[i] = new JButton("Click [" + (i+1) + "]");
25 cp.add(buttons[i]);
26 buttons[i].addActionListener(listener);
27 }
28
29 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
30 setTitle("setLayout() Test");
31 setSize(280, 150);
32 setLocationRelativeTo(null); // center the application window
33 setVisible(true);
34 }
35
36 /** Inner class used as the ActionListener for the Buttons */
37 private class ButtonsListener implements ActionListener {
38 @Override
39 public void actionPerformed(ActionEvent e) {
40 // Swap rows and cols
41 int temp = rows;
42 rows = cols;
43 cols = temp;
44
45 // Set to new rows-by-cols GridLayout
Gangadri K Page 92
Core Java 93

46 cp.setLayout(new GridLayout(rows, cols, 5, 5));


47 cp.validate(); // ask LayoutManager to re-layout
48 }
49 }
50
51 /** The entry main() method */
52 public static void main(String[] args) {
53 // Run GUI codes in the Event-Dispatching thread for thread safety
54 SwingUtilities.invokeLater(new Runnable() {
55 public void run() {
56 new SetLayoutTest(); // Let the constructor do the job
57 }
58 });
59 }
60}

Alternatively, you can also change the rows and columns


of GridLayout via setRows() and setColumns() methods, and doLayout(). For example,

@Override
public void actionPerformed(ActionEvent e) {
// Swap rows and cols
int temp = rows;
rows = cols;
cols = temp;

GridLayout layout = (GridLayout)cp.getLayout();


layout.setRows(rows);
layout.setColumns(cols);
cp.doLayout();
}

3.3  add(), remove(), removeAll() Components from a Container


You can use aContainer.add(aComponent) to add a component into a container. You can also
use aContainer.remove(aComponent) oraContainer.removeAll() to remove a component or all the
components. You need to issue a validate() call to the container after adding or removing components.
Code Example
This example starts with 2 buttons: one to "add" a button and one to "remove" a button. The buttons are arranged
in FlowLayout on the content-pane. For demonstration purpose, I remove all the buttons and re-add all the
buttons.
1import java.awt.*;
2import java.awt.event.*;
3import javax.swing.*;
4
5/** Add or remove components from a container */
6@SuppressWarnings("serial")
7public class AddRemoveComponentsTest extends JFrame {
8 private int numButtons = 2; // number of buttons, init to 2 (1 add, 1 remove)
9 Container cp; // content-pane of JFrame
10 JButton[] buttons; // array of buttons
11 ButtonsListener listener; // an ActionListener instance for all buttons
12
13 /** Constructor to setup the UI components */
14 public AddRemoveComponentsTest() {
15 cp = getContentPane();

Gangadri K Page 93
Core Java 94

16
17 // Create an instance of ActionListener to listen to all Buttons
18 listener = new ButtonsListener();
19 // Call helper method to create numButtons buttons
20 createButtons();
21
22 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
23 setTitle("Add/Remove Components Test");
24 setSize(400, 150);
25 setLocationRelativeTo(null);
26 setVisible(true);
27 }
28
29 /** Create numButtons buttons on content-pane with FlowLayout */
30 private void createButtons() {
31 // For demonstration, all the components are removed, instead of
32 // add or remove selected component.
33 cp.removeAll();
34 cp.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
35
36 // Create buttons
37 buttons = new JButton[numButtons]; // allocate array
38 int i = 0;
39 // Create (numButtons-1) "Add" buttons, but minimum one
40 do {
41 buttons[i] = new JButton("Add");
42 cp.add(buttons[i]);
43 buttons[i].addActionListener(listener);
44 ++i;
45 } while (i < numButtons - 1);
46 // Create a "Remove" button if numButtons > 1
47 if (i == numButtons - 1) {
48 buttons[i] = new JButton("Remove");
49 cp.add(buttons[i]);
50 buttons[i].addActionListener(listener);
51 }
52 cp.validate(); // needed after adding/removing component
53 repaint(); // needed to cleanup dirty background
54 }
55
56 /** Inner class used as the ActionListener for the Buttons */
57 private class ButtonsListener implements ActionListener {
58 @Override
59 public void actionPerformed(ActionEvent e) {
60 // adjust the number of buttons
61 if (e.getActionCommand().equals("Add")) {
62 ++numButtons;
63 } else {
64 if (numButtons >= 2) {
65 --numButtons;
66 }
67 }
68 // Call helper method to create numButtons buttons
69 createButtons();
70 }
71 }
72
73 /** The entry main() method */

Gangadri K Page 94
Core Java 95

74 public static void main(String[] args) {


75 // Run GUI codes in the Event-Dispatching thread for thread safety
76 SwingUtilities.invokeLater(new Runnable() {
77 public void run() {
78 new AddRemoveComponentsTest(); // Let the constructor do the job
79 }
80 });
81 }
82}

3.4  Component Orientation
Most languages from written form left-to-right, but some otherwise. You can set the orientation on Component via:
// java.awt.Component
public void setComponentOrientation(ComponentOrientation o)
// ComponentOrientation.LEFT_TO_RIGHT or RIGHT_TO_LEFT.

Since JDK 1.4, layout managers, such as FlowLayout and BorderLayout, can layout components according to
component-orientation of the container. Some new terms were introduced. For example, in  BorderLayout, instead
of using EAST, WEST, NORHT, SOUTH (which are absolute), the
termLINE_START, LINE_END, PAGE_START, PAGE_END were added which can adjust itself according to the
component orientation. LINE_START is the same as WEST, if the component orientation is LEFT_TO_RIGHT. On the
other hand, it is EAST, if the component orientation is RIGHT_TO_LEFT. Similarly, inFlowLayout's
alignment, LEADING and TRAILING were added in place of LEFT and RIGHT.
Code Example
1import java.awt.*;
2import java.awt.event.*;
3import javax.swing.*;
4
5/** BorderLayout Demo */
6@SuppressWarnings("serial")
7public class BorderLayoutTest extends JFrame {
8 public static final String TITLE = "BorderLayout Demo";
9
10 // Private variables of GUI components
11 private Container cp; // content-pane of this JFrame
12 private JButton btnNorth, btnSouth, btnCenter, btnEast, btnWest;
13 private boolean leftToRight = true;
14
15 /** Constructor to setup the UI components */
16 public BorderLayoutTest() {
17 cp = this.getContentPane();
18 btnNorth = new JButton("PAGE_START [HIDE]");
19 btnSouth = new JButton("PAGE_END [HIDE]");
20 btnWest = new JButton("LINE_START [HIDE]");
21 btnEast = new JButton("LINE_END [HIDE]");
22 btnCenter = new JButton("CENTER [SHOW ALL, CHANGE ORIENTATION]");
23 btnCenter.setPreferredSize(new Dimension(300, 100)); // set size for CENTER
24
25 ActionListener listener = new ButtonListener();
26 btnNorth.addActionListener(listener);
27 btnSouth.addActionListener(listener);
28 btnEast.addActionListener(listener);
29 btnWest.addActionListener(listener);
30 btnCenter.addActionListener(listener);
31
32 // Add all buttons to the content-pane

Gangadri K Page 95
Core Java 96

33 addButtons();
34
35 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // exit if close button clicked
36 setTitle(TITLE); // "this" JFrame sets title
37 pack(); // "this" JFrame packs all its components
38 setLocationRelativeTo(null); // center the application window
39 setVisible(true); // show it
40 }
41
42 /** Helper method to add all buttons to the content-pane */
43 private void addButtons() {
44 cp.removeAll();
45 cp.setComponentOrientation(leftToRight ?
46 ComponentOrientation.LEFT_TO_RIGHT : ComponentOrientation.RIGHT_TO_LEFT);
47 cp.add(btnNorth, BorderLayout.PAGE_START);
48 cp.add(btnSouth, BorderLayout.PAGE_END);
49 cp.add(btnWest, BorderLayout.LINE_START);
50 cp.add(btnEast, BorderLayout.LINE_END);
51 cp.add(btnCenter, BorderLayout.CENTER);
52 cp.validate();
53 }
54
55 /** Inner class used as ActionListener for all buttons */
56 private class ButtonListener implements ActionListener {
57 @Override
58 public void actionPerformed(ActionEvent evt) {
59 JButton source = (JButton)evt.getSource();
60 if (source == btnCenter) {
61 leftToRight = !leftToRight; // toggle
62 addButtons();
63 } else {
64 cp.remove(source);
65 cp.validate();
66 }
67 }
68 }
69
70 /** The entry main() method */
71 public static void main(String[] args) {
72 // Run GUI codes in the Event-Dispatching thread for thread safety
73 SwingUtilities.invokeLater(new Runnable() {
74 @Override
75 public void run() {
76 new BorderLayoutTest(); // Let the constructor do the job
77 }
78 });
79 }
80}

3.5  Absolute Positioning Without a Layout Manager

Gangadri K Page 96
Core Java 97

You could use absolute position instead of a layout manager (such as FlowLayout orBorderLayout) by invoking
method setLayout(null). You can then position you components using the method setBounds(int xTopLeft,
int yTopLeft, int width, int height) . For example:
1import java.awt.*;
2import javax.swing.*;
3
4/** Test Absolute Positioning */
5public class CGAbsolutePositioning extends JFrame {
6 /** Constructor to setup the GUI components */
7 public CGAbsolutePositioning() {
8 Container cp = getContentPane();
9 cp.setLayout(null); // disable layout manager - use absolute layout
10
11 JPanel p1 = new JPanel();
12 p1.setBounds(30, 30, 100, 100);
13 p1.setBackground(Color.RED);
14 cp.add(p1);
15
16 JPanel p2 = new JPanel();
17 p2.setBounds(150, 50, 120, 80);
18 p2.setBackground(Color.BLUE);
19 cp.add(p2);
20
21 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
22 setTitle("Absolute Positioning Demo");
23 setSize(400, 200);
24 setVisible(true);
25 }
26
27 /** The entry main method */
28 public static void main(String[] args) {
29 // Run GUI codes in Event-Dispatching thread for thread safety
30 SwingUtilities.invokeLater(new Runnable() {
31 @Override
32 public void run() {
33 new CGAbsolutePositioning(); // Let the constructor do the job
34 }
35 });
36 }
37}

4.  More on Event-Handling
Both AWT and Swing applications uses the AWT event-handling classes (in package java.awt.event). Swing
added a few new event handling classes (in package javax.swing.event), but they are not frequently used.
AWT GUI Components (such as Button, TextField, and Window) can trigger an AWTEvent upon user’s activation.
Event
Event
User Action Listener
Triggered
interface
Click a Button, JButton ActionEvent ActionListener

Open, iconify, close Frame, JFrame WindowEvent WindowListener

Click a Component, JComponent MouseEvent MouseListener

Change texts in a TextField, JTextField TextEvent TextListener

Type a key KeyEvent KeyListener

Gangadri K Page 97
Core Java 98

Click/Select an item in ItemEvent, ItemListener,


a Choice,JCheckbox, JRadioButton, JComboBox ActionEvent ActionListener
The subclasses of AWTEvent are as follows:

4.1  java.util.EventObject
All event objects extends java.util.EventObject, which takes the source object in this constructor, and provides
a getSource() method.
// Constructor
public EventObject(Object source)

// Method
public Object getSource()

Take note that the constructor takes an Object; and getSource() returns an instance of type Object. You may
need to downcast it back to its original type.
4.2  ActionEvent & ActionListener
An ActionEvent is fired, when an action has been performed by the user. For examples, when the user clicks a
button, chooses a menu item, presses enter key in a text field. The associated ActionListener interface declares
only one abstract method, as follows:
public interface ActionListener extends java.util.EventListener {
public void actionPerformed(ActionEvent evt); // called-back when an action has been
performed
}

From the ActionEvent argument evt, you may use evt.getActionCommand() to get a String related to this


event, for example, the button's label, the String entered into the textfield. This is particularly useful if the
same ActionEvent handler is used to handle multiple source objects (e,g., buttons or textfields), for identifying the
source object that triggers this ActionEvent.
Gangadri K Page 98
Core Java 99

4.3  Swing's Action
Read Swing Tutorial's "How to Use Actions".
A javas.swing.Action is a ActionEvent listener. If two or more components (e.g., a menu item and a button)
perform the same function in response to an ActionEvent, you can use an Action object to specify both
the state and functionality of the components (whereas actionPerformed() defines only the function). For
example, you can specify the states such as the text, icon, shortcut key, tool-tip text, for all the source components.
You can attach an Action object to a component via aComponent.setAction(anAction) method:
1. The component's state (e.g., text, icon) is updated to match the state of the Action.
2. The component adds the Action object as an ActionEvent listener.
3. If the state of the Action changes, the component's state is updated to match the Action.
To create an Action object, you extend AbstractAction to provide the state and implement
the actionPerformed() method to response to theActionEvent.
Example

In this example, a menu-item and a button share the same Action. TheAction object specifies the states (text,
tooltip's text, and a mnemonic alt short-cut key) and override the actionPerformed(). Take note that the label on
the buttons are updated to match the Action's names.
1import javax.swing.*;
2import java.awt.*;
3import java.awt.event.*;
4/**
5 * Test Actions which are ActionListeners that can be applied to more than one sources.
6 * An action can specify the state and functionality of an ActionListener.
7 */
8@SuppressWarnings("serial")
9public class TestAction extends JFrame {
10 private JTextField tfCount;
11 private int count;
12
13 /** Constructor to setup the GUI */
14 public TestAction() {
15 // Create the Actions shared by the button and menu-item
16 Action countUpAction = new CountUpAction("Count Up",
17 "To count up", new Integer(KeyEvent.VK_U));
18 Action countDownAction = new CountDownAction("Count Down",
19 "To count down", new Integer(KeyEvent.VK_D));
20 Action resetAction = new ResetAction("Reset",
21 "To reset to zero", new Integer(KeyEvent.VK_R));
22
23 Container cp = getContentPane();
24 cp.setLayout(new FlowLayout());
25
26 // Create buttons
27 cp.add(new JLabel("Counter: "));
28 tfCount = new JTextField("0", 8);
29 tfCount.setHorizontalAlignment(JTextField.RIGHT);
30 cp.add(tfCount);
31 JButton btnCountUp = new JButton();
32 cp.add(btnCountUp);

Gangadri K Page 99
Core Java 100

33 JButton btnCountDown = new JButton();


34 cp.add(btnCountDown);
35 JButton btnReset = new JButton();
36 cp.add(btnReset);
37 // Set actions for buttons
38 btnCountUp.setAction(countUpAction);
39 btnCountDown.setAction(countDownAction);
40 btnReset.setAction(resetAction);
41
42 // Create menu-bar
43 JMenuBar menuBar = new JMenuBar();
44 JMenu menu;
45 JMenuItem menuItem;;
46
47 // Create the first menu
48 menu = new JMenu("Count");
49 menu.setMnemonic(KeyEvent.VK_C);
50 menuItem = new JMenuItem(countUpAction); // allocate menu-item and set action
51 menu.add(menuItem);
52 menuItem = new JMenuItem(countDownAction); // allocate menu-item and set action
53 menu.add(menuItem);
54 menuBar.add(menu);
55
56 // Create the second menu
57 menu = new JMenu("Reset");
58 menu.setMnemonic(KeyEvent.VK_R);
59 menuItem = new JMenuItem(resetAction); // allocate menu-item and set action
60 menu.add(menuItem);
61 menuBar.add(menu);
62
63 setJMenuBar(menuBar); // "this" JFrame sets menu-bar
64 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
65 setTitle("Action Test");
66 setSize(550, 120);
67 setVisible(true);
68 }
69
70 /**
71 * Action inner classes
72 */
73 public class CountUpAction extends AbstractAction {
74 /** Constructor */
75 public CountUpAction(String name, String shortDesc, Integer mnemonic) {
76 super(name);
77 putValue(SHORT_DESCRIPTION, shortDesc);
78 putValue(MNEMONIC_KEY, mnemonic);
79 }
80
81 @Override
82 public void actionPerformed(ActionEvent e) {
83 ++count;
84 tfCount.setText(count + "");
85 }
86 }
87
88 public class CountDownAction extends AbstractAction {
89 /** Constructor */
90 public CountDownAction(String name, String shortDesc, Integer mnemonic) {

Gangadri K Page 100


Core Java 101

91 super(name);
92 putValue(SHORT_DESCRIPTION, shortDesc);
93 putValue(MNEMONIC_KEY, mnemonic);
94 }
95
96 @Override
97 public void actionPerformed(ActionEvent e) {
98 --count;
99 tfCount.setText(count + "");
100 }
101 }
102
103 public class ResetAction extends AbstractAction {
104 /** Constructor */
105 public ResetAction(String name, String shortDesc, Integer mnemonic) {
106 super(name);
107 putValue(SHORT_DESCRIPTION, shortDesc);
108 putValue(MNEMONIC_KEY, mnemonic);
109 }
110
111 @Override
112 public void actionPerformed(ActionEvent e) {
113 count = 0;
114 tfCount.setText(count + "");
115 }
116 }
117
118 /** The entry main() method */
119 public static void main(String[] args) {
120 // Run GUI codes in the Event-Dispatching thread for thread safety
121 javax.swing.SwingUtilities.invokeLater(new Runnable() {
122 public void run() {
123 new TestAction(); // Let the constructor does the job
124 }
125 });
126 }
127}

4.4  WindowEvent & WindowListener/WindowAdapter
Interface WindowListener is used for handling WindowEvent triggered via the three special buttons (minimize,
maximize/restore down, and close) on the top-right corner of the window or other means. There are 7 abstract
methods declared in the interface, as follows:
public interface WindowListener extends java.util.EventListener {
public void windowClosing(WindowEvent evt);
// called-back when the user attempt to close this window, most commonly-used handler
public void windowActivated(WindowEvent evt);
// called-back when this window is set to the active window
public void windowDeactivated(WindowEvent evt);
// called-back when this window is no longer the active window
public void windowOpened(WindowEvent evt);
// called-back when this window is first made to be visible
public void windowClosed(WindowEvent evt);
// called-back when the window has been closed
public void windowIconified(WindowEvent evt);
// called-back when this window is minimized
public void windowDeiconified(WindowEvent evt);
// called-back when this window is change from minimize to normal state

Gangadri K Page 101


Core Java 102

The most commonly-used method is WindowClosing(), which is called when the user attempts to close this
window via the "window-close" button or "file-exit" menu item.
// Sample handler for windowClosing()
@Override
public void WindowClosing(WindowEvent evt) {
// Ask user to confirm
......
// Perform clean up operations
......
System.exit(0); // Terminate the program
}
WindowAdapter
A WindowEvent listener must implement the WindowListener interface and provides implementation to ALL the 7
abstract methods declared. An empty-body implementation is required even if you are not using that particular
handler. To improve productivity, an adapter class calledWindowAdapter is provided, which
implements WindowListener interface and provides default implementation to all the 7 abstract methods. You can
then derive a subclass from WindowAdapter and override only methods of interest and leave the rest to their
default implementation.
This example shows how to extend a WindowAdapter class, using an anonymous inner class, to handle a window-
closing event.

public class GUIApplication extends JFrame {


public GUIApplication() { // Constructor
......
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
}
......
}
JFrame's setDefaultCloseOperation()
In Swing's JFrame, a special method called setDefaultCloseOperation() is provided to handle clicking of the
"window-close" button. For example, to exit the program upon clicking the close-window button, you can use the
following instead of WindowListener or WindowAdapter.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // exit program upon clicking window-close
button

Similarly, most of the event listener interface has its equivalent adapter,
e.g., MouseAdapter for MouseListener interface, KeyAdapter forKeyListener interface, MouseMotionAdapter for M
ouseMotionListener interface. There is no ActionAdapter for ActionListener, because there is only one abstract
method inside the ActionListener interface, with no need for an adapter.
A word of caution: If you implement the WindowListener yourself and misspell a method name
says windowClosing() to winowClosing(), the compiler will signal an error to notify you
that windowClosing() method was not implemented. However, if you extend from WindowAdapter class and
misspell a method name, the compiler treats the misspell method as a new method in the subclass, and uses the
default implementation provided by WindowAdapter for handling that event. This small typo error took me a few
agonizing hours to debug. This problem is resolved via the annotation @Override introduced in JDK 1.5, which tells
the compiler to issue an error if the annotated method does not override its superclass.
Gangadri K Page 102
Core Java 103

4.5  KeyEvent & KeyListener/KeyAdapter
The KeyListener interface defines three abstract methods:
void keyTyped(KeyEvent evt)
// Called-back when a key has been typed (pressed followed by released)
void keyPressed(KeyEvent evt)
// Called-back when a key has been pressed
void keyReleased(KeyEvent evt)
// Callback when a key has been released

There are two kinds of key events:


1. The typing of a valid character, e.g., 'a', 'A'. This is called a key-typed event.
2. The pressing or releasing of a key, e.g., up-arrow, enter, 'a', shift+'a'. This is a key-pressed or key-
released event.
Use keyTyped() to process key-typed event, which produces a valid Unicode character. You can
use evt.getKeyChar() to retrieve the char typed.getKeyChar() can differentiate between 'a' and 'A' (pressed
shift+'a').
You can use keyPressed() and keyReleased() for all the keys, character key or others (such as up-arrow and
enter). You can useevt.getKeyCode() to retrieve the int Virtual Key (VK) code,
e.g., KeyEvent.VK_UP, KeyEvent.VK_ENTER, KeyEvent.VK_A. You can also useevt.getKeyChar() to retrieve the
unicode character, if the event produced a valid Unicode character.
getKeyCode() vs. getKeyChar()
 If you press 'a' key, getKeyChar() returns 'a' and getKeyCode() returns VK_A.
 If you press shift+'a', two key-pressed events and one key-typed event
triggered. getKeyChar() returns 'A' and getKeyCode() returnsVK_SHIFT in the first key-pressed event
and VK_A in the second event. The first key-pressed event is often ignored by the program.

Notice that Virtual Key codes, key-char are used, instead of actual key code, to ensure platform and keyboard-
layout independent.

For Example,

1import java.awt.*;
2import java.awt.event.*;
3import javax.swing.*;
4
5/** Test KeyListener */
6public class KeyListenerTest extends JFrame implements KeyListener {
7 /** Constructor to setup the GUI */
8 public KeyListenerTest() {
9 Container cp = getContentPane();
10 cp.addKeyListener(this);
11 // Need to enables receiving of key inputs for this GUI component.
12 cp.setFocusable(true);
13 // "May" need to request keyboard focus on this component.
14 cp.requestFocus();
15
16 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
17 setTitle("Testing Key Listener");
18 setSize(300, 200);
19 setVisible(true);
20 }
21
22 @Override
23 public void keyTyped(KeyEvent e) {

Gangadri K Page 103


Core Java 104

24 char keyChar = e.getKeyChar();


25 System.out.println("keyTyped: Key char is " + keyChar);
26 }
27
28 @Override
29 public void keyPressed(KeyEvent e) {
30 int keyCode = e.getKeyCode();
31 char keyChar = e.getKeyChar();
32 System.out.println("keyPressed: VK Code is " + keyCode + ", Key char is " + keyChar);
33 }
34
35 @Override
36 public void keyReleased(KeyEvent e) {} // Ignored
37
38 /** The entry main method */
39 public static void main(String[] args) {
40 // Run GUI codes on the Event-Dispatching thread for thread safety */
41 SwingUtilities.invokeLater(new Runnable() {
42 @Override
43 public void run() {
44 new KeyListenerTest(); // Let the constructor do the job
45 }
46 });
47 }
48}

Try pressing 'a', 'A' (shift+'a'), enter, up-arrow, etc, and observe the key-char and VK-code produced
by keyTyped() and keyPressed().

Below is a sample handler for a key listener:

@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP: ......; break
case KeyEvent.VK_DOWN: ......; break
case KeyEvent.VK_LEFT: ......; break
case KeyEvent.VK_RIGHT: ......; break
}
}
 
@Override
public void keyTyped(KeyEvent e) {
// Can also be placed in keyPressed()
switch (e.getKeyChar()) {
case 'w': ......; break
case 'a': ......; break
case 'z': ......; break
case 's': ......; break
}
}

The commonly-used virtual key codes are:

Gangadri K Page 104


Core Java 105

 VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN: arrow keys


 VK_KP_LEFT, VK_KP_RIGHT, VK_KP_UP, VK_KP_DOWN: arrow key on numeric keypad
 VK_0 to VK_9, VK_A to VK_Z: numeric and alphebet keys. Also produce a Unicode char for the getKeyChar()
 VK_ENTER, VK_TAB, VK_BACKSPACE
4.6  MouseEvent & MouseListener/MouseAdapter
The MouseListener interface is associated with MouseEvent (triggered via mouse-button press, release and click
(press followed by release)) on the source object. It declares 5 abstract methods:
public void mouseClicked(MouseEvent evt)
// Called-back when a mouse button has been clicked (pressed followed by released) on the
source
public void mouseEntered(MouseEvent evt)
// Called-back when the mouse enters the source
public void mouseExited(MouseEvent evt)
// Called-back when the mouse exits the source
public void mousePressed(MouseEvent evt)
// Called-back when a mouse button has been pressed on the source
public void mouseReleased(MouseEvent evt)
// Called-back when a mouse button has been released on the source

From the MouseEvent argument evt, you can:


 use evt.getX() and evt.getY() to retrieve the (x, y) coordinates of the location of the mouse.
 use evt.getXOnScreen() and evt.getYOnScreen() to retrieve the absolute(x, y) coordinates on the screen.
 use evt.getClickCount() to retrieve the number of clicks, e.g., 2 for double-click.
 use evt.getButton() to determine which button
(MouseEvent.BUTTON1, MouseEvent.BUTTON2, MouseEvent.BUTTON3, orMouseEvent.NOBUTTON) is clicked.
An adapter class MouseAdapter is available, which provides default (empty) implementation to the
5 abstract methods declared in theMouseListener interface. You can create a mouse listener by subclassing
the MouseAdapter and override the necessary methods. For example,
// Use an anonymous inner class (extends MouseAdapter) as mouse listener
aSource.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent evt) {
// ... do something ...
}
});

4.7  MouseEvent & MouseMotionListener/MouseMotionAdapter
The MouseEvent is associated with two interfaces: MouseListener (for mouse
clicked/pressed/released/entered/exited) described earlier; and the MouseMotionListener (for mouse moved and
dragged). The MouseMotionListener interface declares 2 abstract methods:

public void mouseDragged(MouseEvent evt);


// Called-back when a mouse button is pressed on a source and then dragged
public void mouseMoved(MouseEvent evt);
// Called-back when the mouse has been moved onto a source but no buttons pressed

From the MouseEvent argument, you can use getX(), getY(), getXOnScreen(), getYOnScreen() to find the


position of the mouse cursor, as described earlier.
The mouseDragged() can be used to draw a arbitrary-shape line using mouse-pointer. The mouse-dragged event
starts when you pressed a mouse button, and will be delivered continuously until the mouse-button is released.
For example,

@Override

Gangadri K Page 105


Core Java 106

public void MouseDragged(MouseEvent evt) {


// add evt.getX() and evt.getY() to a list of (x, y).
// you can then use drawPolyline() method of the Graphics class to draw this line
......
}

Swing's MouseInputListener/MouseInputAdapter
Swing added a new event listener called MouseInputListener which
combines MouseListener and MouseMotionListener as follows. You only need to implement one interface
instead of two interfaces.

interface javax.swing.event.MouseInputListener
extends java.awt.MouseListener, java.awt.MouseMotionListener {
// Empty body - no additional method declared
}

Example: Using mouse-drag to draw a red rectangle. (You need to understand "Custom Graphics" - the next article
- to read this program.)

1import java.awt.*;
2import java.awt.event.*;
3import javax.swing.*;
4import javax.swing.event.*;
5
6/** Test mouse-dragged */
7@SuppressWarnings("serial")
8public class MouseDragDemo extends JFrame {
9 private int startX, startY, endX, endY; // of a rectangle
10 private JLabel statusBar; // display the status
11
12 /** Constructor to setup the GUI */
13 public MouseDragDemo() {
14 // Define an anonymous inner class extends JPanel for custom drawing
15 // and allocate an instance
16 JPanel drawPanel = new JPanel() {
17 @Override
18 public void paintComponent(Graphics g) {
19 super.paintComponent(g); // paint parent's background
20 g.setColor(Color.RED);
21 // drawRect() uses x, y, width and height instead of (x1,y1) and (x2,y2)
22 int x = (startX < endX) ? startX : endX;
23 int y = (startY < endY) ? startY : endY;
24 int width = endX - startX + 1;
25 if (width < 0) width = -width;

Gangadri K Page 106


Core Java 107

26 int height = endY - startY + 1;


27 if (height < 0) height = -height;
28 g.drawRect(x, y, width, height);
29 }
30 };
31
32 statusBar = new JLabel();
33 drawPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
34 drawPanel.add(statusBar);
35
36 // Allocate an instance of MyMouseDraggedListener
37 // and used it as MouseListener and MouseMotionListener
38 MyMouseDraggedListener listener = new MyMouseDraggedListener();
39 drawPanel.addMouseListener(listener);
40 drawPanel.addMouseMotionListener(listener);
41
42 setContentPane(drawPanel);
43 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
44 setTitle("Mouse-Drag Demo");
45 setSize(400, 250);
46 setVisible(true);
47 }
48
49 private class MyMouseDraggedListener extends MouseInputAdapter {
50 @Override
51 public void mousePressed(MouseEvent evt) {
52 startX = evt.getX();
53 startY = evt.getY();
54 statusBar.setText("(" + startX + "," + startY + ")");
55 }
56 @Override
57 public void mouseDragged(MouseEvent evt) {
58 endX = evt.getX();
59 endY = evt.getY();
60 statusBar.setText("(" + endX + "," + endY + ")");
61 repaint(); // Called back paintComponent()
62 }
63 @Override
64 public void mouseReleased(MouseEvent evt) {
65 endX = evt.getX();
66 endY = evt.getY();
67 statusBar.setText("(" + endX + "," + endY + ")");
68 repaint(); // Called back paintComponent()
69 }
70 }
71
72 /** The entry main method */
73 public static void main(String[] args) {
74 // Run GUI codes on the Event-Dispatching thread for thread safety
75 SwingUtilities.invokeLater(new Runnable() {
76 @Override
77 public void run() {
78 new MouseDragDemo(); // Let the constructor do the job
79 }
80 });
81 }
82}

Gangadri K Page 107


Core Java 108

[TODO] GUI programming is huge. Need to separate into a few articles.

Gangadri K Page 108

You might also like