Core Java AWT and Swings
Core Java AWT and Swings
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
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
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:
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();
}
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
Gangadri K Page 5
Core Java 6
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);
Example
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);
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
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
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
Gangadri K Page 7
Core Java 8
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.
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);
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)
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.
Gangadri K Page 13
Core Java 14
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:
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
btnCount.addActionListener(this);
Gangadri K Page 15
Core Java 16
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
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.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:
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:
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
Gangadri K Page 22
Core Java 23
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
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
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}
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
Gangadri K Page 28
Core Java 29
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}
btnCount.addActionListener(new BtnCountListener());
@Override
public void actionPerformed(ActionEvent e) {
frame.count++;
frame.tfCount.setText(frame.count + "");
}
}
Gangadri K Page 30
Core Java 31
});
Gangadri K Page 31
Core Java 32
// 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,
Gangadri K Page 32
Core Java 33
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}
Gangadri K Page 34
Core Java 35
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
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}
Gangadri K Page 37
Core Java 38
16 inner3.printMessage();
17 }
18}
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
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.
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}
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.
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);
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) { ... }
......
}
Note: These classes were designed before the introduction of generic in JDK 1.5, which supports the passing of
type as argument.
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);
}
});
}
}
Gangadri K Page 43
Core Java 44
Gangadri K Page 44
Core Java 45
For example,
Gangadri K Page 45
Core Java 46
......
Container's getLayout()
You can get the current layout via Container's getLayout().
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
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
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}
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.
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
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
Gangadri K Page 56
Core Java 57
Gangadri K Page 57
Core Java 58
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
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,
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
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
Gangadri K Page 60
Core Java 61
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.
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
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,
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
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
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.
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}
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
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}
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
Gangadri K Page 74
Core Java 75
[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
Gangadri K Page 75
Core Java 76
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().
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
Gangadri K Page 80
Core Java 81
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
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}
// Display a message
public static void showMessageDialog(Component parentComponent, Object message,
[String title], [int messageType], [Icon icon])
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
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}
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.
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();
}
For example,
Gangadri K Page 89
Core Java 90
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. }
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 customize the look and feel, which is beyond the scope of this article.
[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
@Override
public void actionPerformed(ActionEvent e) {
// Swap rows and cols
int temp = rows;
rows = cols;
cols = temp;
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
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}
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
Gangadri K Page 97
Core Java 98
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
}
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
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
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.
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
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) {
Try pressing 'a', 'A' (shift+'a'), enter, up-arrow, etc, and observe the key-char and VK-code produced
by keyTyped() and keyPressed().
@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
}
}
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:
@Override
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;