GUI Programming - Java Programming Tutorial
GUI Programming - Java Programming Tutorial
1 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
1. Introduction
2. Programming GUI with AWT
2.1 AWT Packages
2.2 Containers and Components
2.3 AWT Container Classes
2.4 AWT Component Classes
2.5 Example 1: AWTCounter
2.6 Example 2: AWTAccumulator
3. AWT Event-Handling
3.1 Revisit Example 1 AWTCounter
3.2 Revisit Example 2 AWTAccumulator
1. Introduction
So far, we have covered most of the basic constructs of Java and introduced the important
concept of Object-Oriented Programming (OOP). As discussed, OOP permits higher level of
abstraction than the traditional procedural-oriented languages (such as C and Pascal). OOP
lets you think in the problem space rather than the computer's bits and bytes and
instruction sequences. You can create high-level abstract data types called classes to mimic
real-life things and represent entities in the problem space. These classes are self-contained
and are reusable.
In this article, I shall show you how you can reuse the graphics classes provided in JDK for
constructing your own Graphical User Interface (GUI) applications. Writing your own
graphics classes (re-inventing the wheels) will take you many years! These graphics classes,
developed by expert programmers, are highly complex and involve many advanced Java
concepts. However, re-using them are not so difficult, if you follow the API documentation,
samples and templates provided.
I shall assume you have a good grasp of OOP, including inheritance and polymorphism
(otherwise, read the earlier articles). I will describe another important concept called nested
class (or inner class) in this article.
There are two sets of Java APIs for graphics programming: AWT (Abstract Windowing
Toolkit) and Swing.
1. AWT API was introduced in JDK 1.0. Most of the AWT components have become
obsolete and should be replaced by newer Swing components.
2. Swing API, a much more comprehensive set of graphics libraries that enhances the
AWT, was introduced as part of Java Foundation Classes (JFC) after the release of JDK
1.1. JFC consists of Swing, Java2D, Accessibility, Internationalization, and Pluggable
Look-and-Feel Support APIs. JFC was an add-on to JDK 1.1 but has been integrated
into core Java since JDK 1.2.
Other than AWT/Swing Graphics APIs provided in JDK, others have also provided Graphics
APIs that work with Java, such as Eclipse's Standard Widget Toolkit (SWT) (used in Eclipse),
Google Web Toolkit (GWT) (used in Android), 3D Graphics API such as Java bindings for
OpenGL (JOGL) and Java3D.
You need to check the JDK API specification (http://docs.oracle.com/javase/7/docs
/api/index.html) for the AWT and Swing APIs while reading this chapter. The best online
reference for Graphics programming is the "Swing Tutorial" @ http://docs.oracle.com/javase
/tutorial/uiswing/. For advanced 2D graphics programming, read "Java 2D Tutorial" @
http://docs.oracle.com/javase/tutorial/2d/index.html.
Introduction
Swing's Features
Using Swing API
Swing Program Template
Swing Example 1: SwingCounter
3/3/2015 10:35 AM
2 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
11.2 Eclipse
3/3/2015 10:35 AM
3 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
import java.awt.Frame;
An AWT Dialog is a "pop-up window" used for interacting with the users. A
Dialog has a title-bar (containing an icon, a title and a close button) and a
content display area, as illustrated.
An AWT Applet (in package java.applet) is the top-level container for an
applet, which is a Java program running inside a browser. Applet will be
discussed in the later chapter.
3/3/2015 10:35 AM
4 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
// Label.LEFT
// Label.RIGHT
// Label.CENTER
These three constants are defined for specifying the alignment of the Label's text.
Public Methods
// Examples
public String getText();
public void setText(String strLabel);
3/3/2015 10:35 AM
5 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
The getText() and setText() methods can be used to read and modify the Label's text. Similarly, the getAlignment() and
setAlignment() methods can be used to retrieve and modify the alignment of the text.
//
//
//
//
//
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 identifier for 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 Label instance 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);
Constructors
public Button(String buttonLabel);
// Construct a Button with the given label
public Button();
// Construct a Button with empty label
The Button class has two constructors. The first constructor creates a Button object with the given label painted over the button. The
second constructor creates a Button object with no label.
Public Methods
public String getLabel();
// Get the label of this Button instance
public void setLabel(String buttonLabel);
// Set the label of this Button instance
public void setEnable(boolean enable);
3/3/2015 10:35 AM
6 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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");
add(btnColor);
...
btnColor.setLabel("green");
btnColor.getLabel();
...
add(Button("Blue"));
// Create an
Constructors
public TextField(String strInitialText, int columns);
// Construct a TextField instance with the given initial text string with the number of columns.
public TextField(String strInitialText);
// Construct a TextField instance with the given initial text string.
public TextField(int columns);
// Construct a TextField instance with the number of columns.
Public Methods
public String getText();
// Get the current text on this TextField instance
public void setText(String strText);
// Set the display text on this TextField instance
public void setEditable(boolean editable);
// Set this TextField to editable (read/write) or non-editable (read-only)
Event
Hitting the "ENTER" key on a TextField fires a ActionEvent, and triggers a certain programmed action.
Example
TextField tfInput = new TextField(30); // Declare and allocate an TextField instance called tfInput
add(tfInput);
// "this" Container adds the TextField
TextField tfResult = new TextField(); // Declare and allocate an TextField instance called tfResult
tfResult.setEditable(false) ;
// Set to read-only
add(tfResult);
// "this" Container adds the TextField
......
// Read an int from TextField "tfInput", square it, and display on "tfResult".
// getText() returns a String, need to convert to int
int number = Integer.parseInt(tfInput.getText());
number *= number;
// setText() requires a String, need to convert the int number to String.
tfResult.setText(number + "");
Take note that getText()/SetText() operates on String. You can convert a String to a primitive, such as int or double via
static method Integer.parseInt() or Double.parseDouble(). To convert a primitive to a String, simply concatenate the
3/3/2015 10:35 AM
7 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import java.awt.*;
import java.awt.event.*;
// construct Label
// "super" Frame adds Label
// construct Button
// "super" Frame adds Button
btnCount.addActionListener(this);
// Clicking Button source fires ActionEvent
// btnCount registers this instance as ActionEvent listener
setTitle("AWT Counter");
setSize(250, 100);
//
//
//
//
System.out.println(this);
System.out.println(lblCount);
System.out.println(tfCount);
System.out.println(btnCount);
setVisible(true);
//
//
//
//
System.out.println(this);
System.out.println(lblCount);
System.out.println(tfCount);
System.out.println(btnCount);
}
/** The entry main() method */
public static void main(String[] args) {
// Invoke the constructor to setup the GUI, by allocating an instance
3/3/2015 10:35 AM
8 of 52
50
51
52
53
54
55
56
57
58
59
60
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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.
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());
3/3/2015 10:35 AM
9 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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)
// Before setVisible(), all components are invalid (top-left (x,y), width/height are invalid)
// After setVisible(), all components are valid
AWTCounter[frame0,0,0,250x100,layout=java.awt.FlowLayout,title=AWT Counter,resizable,normal]
// valid and visible (not hidden)
java.awt.Label[label0,20,41,58x23,align=left,text=Counter]
// Top-left (x,y) at (20,41) relative to the parent Frame; width/height = 58x23
java.awt.TextField[textfield0,83,41,94x23,text=0,selection=0-0]
// Top-left (x,y) at (83,41) relative to the parent Frame; width/height = 94x23; no text selected (0-0)
java.awt.Button[button0,182,41,47x23,label=Count]
// Top-left (x,y) at (182,41) relative to the parent Frame; width/height = 47x23
import java.awt.*;
import java.awt.event.*;
3/3/2015 10:35 AM
10 of 52
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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).
3/3/2015 10:35 AM
11 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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 subscribepublish or observable-observer design pattern.
Called
Called
Called
Called
Called
back
back
back
back
back
upon
upon
upon
when
when
mouse-button pressed
mouse-button released
mouse-button clicked (pressed and released)
mouse pointer entered the component
mouse pointer exited the component
Secondly, all the listeners interested in the XxxEvent must implement the XxxListener interface. That is, the listeners must
provide their own implementations (i.e., programmed responses) to all the abstract methods declared in the XxxListener
interface. In this way, the listenser(s) can response to these events appropriately. For example,
// An example of MouseListener, which provides implementation to the handler methods
class MyMouseListener implement MouseListener {
@Override
public void mousePressed(MouseEvent e) {
System.out.println("Mouse-button pressed!");
}
@Override
public void mouseReleased(MouseEvent e) {
System.out.println("Mouse-button released!");
}
@Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse-button clicked (pressed and released)!");
3/3/2015 10:35 AM
12 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
}
@Override
public void mouseEntered(MouseEvent e) {
System.out.println("Mouse-pointer entered the source component!");
}
@Override
public void mouseExited(MouseEvent e)
{
System.out.println("Mouse exited-pointer the source component!");
}
}
Thirdly, in the source, we need to maintain a list of listener object(s), and define two methods: addXxxListener() and
removeXxxListener() to add and remove a listener from this list. The signature of the methods are:
public void addXxxListener(XxxListener l);
public void removeXxxListener(XxxListener l);
Take note that all the listener(s) interested in the XxxEvent must implement the XxxListener interface. That is, they are
sub-type of the XxxListener. 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 eventlistener interface. The source object then registers listener object via the addXxxListener() method:
aSource.addXxxListener(alistener);
3/3/2015 10:35 AM
13 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
tfCount.setText(count + "");
}
}
The source object registers listener via the addActionListener(). In this example, the source btnCount (Button) adds "this"
object as a listener via:
btnCount.addActionListener(this);
Note that addActionListener() takes an argument of the type ActionListener. "this", which implements ActionListener
interface (i.e., a subclass of ActionListener), is upcasted and passed to the addActionListener() method.
Upon button-click, the btnCount creates an ActionEvent object, and calls back the actionPerformed(ActionEvent) method of
all its registered listener(s) with the ActionEvent object created:
ActionEvent evt = new ActionEvent( ...... );
listener.actionPerformed(evt);
// for all its listener(s)
3/3/2015 10:35 AM
14 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
5. The ActionEvent listener (this class) is required to implement the ActionListener interface, and override the
actionPerformed() method to provide the programmed response upon activation.
WindowEvent
listeners)
The following program added support for "close-window button" to Example 1: AWTCounter.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.awt.*;
import java.awt.event.*;
btnCount.addActionListener(this);
// btnCount fires ActionEvent to its registered ActionEvent listener
3/3/2015 10:35 AM
15 of 52
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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).
3. We select this object as the WindowEvent listener (for simplicity)
4. We register this object as the WindowEvent listener to the source Frame via method addWindowListener(this).
5. The WindowEvent listener (this class) is required to implement the WindowListener interface, which declares 7 abstract
methods:
windowOpened(),
windowClosed(),
windowClosing(),
windowActivated(),
windowDeactivated(),
3/3/2015 10:35 AM
16 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class MouseEventDemo extends Frame implements MouseListener {
// Private variables
private TextField tfMouseX; // to display mouse-click-x
private TextField tfMouseY; // to display mouse-click-y
// Constructor - Setup the UI
public MouseEventDemo() {
setLayout(new FlowLayout()); // "super" frame sets layout
// Label
add(new Label("X-Click: ")); // "super" frame adds component
// TextField
tfMouseX = new TextField(10); // 10 columns
tfMouseX.setEditable(false); // read-only
add(tfMouseX);
// "super" frame adds component
// Label
3/3/2015 10:35 AM
17 of 52
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
mousePressed(MouseEvent e) { }
mouseReleased(MouseEvent e) { }
mouseEntered(MouseEvent e) { }
mouseExited(MouseEvent e) { }
In this example, we setup a GUI with 4 components (two Labels and two non-editable TextFields), inside a top-level container
Frame, arranged in FlowLayout.
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).
3/3/2015 10:35 AM
18 of 52
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import
import
import
import
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
java.awt.*;
java.awt.event.MouseEvent;
java.awt.event.MouseListener;
java.awt.event.MouseMotionListener;
3/3/2015 10:35 AM
19 of 52
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
}
// Not Used, but need to provide an empty body for compilation
@Override
public void mousePressed(MouseEvent e) { }
@Override
public void mouseReleased(MouseEvent e) { }
@Override
public void mouseEntered(MouseEvent e) { }
@Override
public void mouseExited(MouseEvent e) { }
/** MouseMotionEvent handlers */
// Called back when the mouse-pointer has been moved
@Override
public void mouseMoved(MouseEvent e) {
tfMousePositionX.setText(e.getX() + "");
tfMousePositionY.setText(e.getY() + "");
}
// Not Used, but need to provide an empty body for compilation
@Override
public void mouseDragged(MouseEvent e) { }
}
register
this
object
as
the
listener
to
super
Frame
via
method
addMouseListener(this)
and
addMouseMotionListener(this).
4. The MouseMotionListener (this class) needs to implement 2 abstract methods: mouseMoved() and mouseDragged() declared
in the MouseMotionListener interface.
5. We override the mouseMoved() to display the (x, y) position of the mouse pointer. We ignore the MouseDragged() handler by
providing an empty body for compilation.
3/3/2015 10:35 AM
20 of 52
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
// An AWT GUI program inherits from the top-level container java.awt.Frame
public class KeyEventDemo extends Frame implements KeyListener {
// This class acts as KeyEvent Listener
private TextField tfInput; // single-line TextField to receive tfInput key
private TextArea taDisplay; // multi-line TextArea to taDisplay result
/** Constructor to setup the GUI */
public KeyEventDemo() {
setLayout(new FlowLayout()); // "super" frame sets to FlowLayout
add(new Label("Enter Text: "));
tfInput = new TextField(10);
add(tfInput);
taDisplay = new TextArea(5, 40); // 5 rows, 40 columns
add(taDisplay);
tfInput.addKeyListener(this);
// tfInput TextField fires KeyEvent to its registered KeyListeners
// tfInput adds "this" object as a KeyEvent listener
setTitle("KeyEvent Demo"); // "super" Frame sets title
setSize(400, 200);
// "super" Frame sets initial size
setVisible(true);
// "super" Frame shows
}
/** The entry main() method */
public static void main(String[] args) {
new KeyEventDemo(); // Let the constructor do the job
}
/** KeyEvent handlers */
// Called back when a key has been typed (pressed and released)
@Override
public void keyTyped(KeyEvent e) {
taDisplay.append("You have typed " + e.getKeyChar() + "\n");
}
// Not Used, but need to provide an empty body for compilation
@Override
public void keyPressed(KeyEvent e) { }
@Override
public void keyReleased(KeyEvent e) { }
}
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).
5. The KeyEvent listener (this class) needs to implement the KeyListener interface, which declares 3 abstract methods:
keyTyped(), keyPressed(), keyReleased().
6. We override the keyTyped() to display key typed on the display TextArea. We ignore the keyPressed() and keyReleased().
3/3/2015 10:35 AM
21 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
The Observer design pattern (aka Publish-Subscribe or Observable-Observer) is one of the 23 GoF's design patterns. Whenever the
source's state changes, it notifies all its registered listener.
The source and listener are bound via the interface XxxListener, which defines a set of handlers. The source maintain a list of
registered
listeners,
and
two
methods:
addXxxListener() and
removeXxxListener().
Both
addXxxListener()
and
removeXxxListener() takes an argument of XxxListener. Hence, a listener object must implement XxxListener in order to be
registered. Whenever the source's state changes, it invokes a particular handler of all the registered listeners. The interface guarantees
the existence of such handler in the listener.
Event: LightEvent.java
1
2
3
4
5
6
7
8
/** LightEvent */
import java.util.EventObject;
public class LightEvent extends EventObject {
public LightEvent (Object src) {
super(src);
}
}
Source: Light.java
1
3/3/2015 10:35 AM
22 of 52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
import java.util.*;
public class Light {
// Status - on (true) or off (false)
private boolean on;
// Listener list
private List<LightListener> listeners = new ArrayList<LightListener>();
/** Constructor */
public Light() {
on = false;
System.out.println("Light: constructed and off");
}
/** Add the given LightListener */
public void addLightListener(LightListener listener) {
listeners.add(listener);
System.out.println("Light: added a listener");
}
/** Remove the given LightListener */
public void removeLightListener(LightListener listener) {
listeners.remove(listener);
System.out.println("Light: removed a listener");
}
/** Turn on this light */
public void turnOn() {
if (!on) {
on = !on;
System.out.println("Light: turn on");
notifyListener();
}
}
/** Turn off this light */
public void turnOff() {
if (on) {
on = !on;
System.out.println("Light: turn off");
notifyListener();
}
}
/** Construct an LightEvent and notify all its registered listeners */
private void notifyListener() {
LightEvent evt = new LightEvent(this);
for (LightListener listener : listeners) {
if (on) {
listener.lightOn(evt);
} else {
listener.lightOff(evt);
}
}
}
}
Listener: LightWatcher.java
1
2
3
4
5
6
7
8
9
3/3/2015 10:35 AM
23 of 52
10
11
12
13
14
15
16
17
18
19
20
21
22
23
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
that light is on
that light is on
that light is on
3/3/2015 10:35 AM
24 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
import java.awt.*;
import java.awt.event.*;
// An AWT GUI program inherits from the top-level container java.awt.Frame
public class AWTCounterNamedInnerClass extends Frame {
// This class is NOT a ActionListener, hence, it does not implement ActionListener
// The event-handler actionPerformed() needs to access these "private" variables
private TextField tfCount;
private int count = 0;
/** Constructor to setup the GUI */
public AWTCounterNamedInnerClass () {
setLayout(new FlowLayout()); // "super" Frame sets to FlowLayout
add(new Label("Counter"));
// anonymous instance of Label
tfCount = new TextField("0", 10);
tfCount.setEditable(false);
// read-only
add(tfCount);
// "super" Frame adds tfCount
Button btnCount = new Button("Count");
add(btnCount);
// "super" Frame adds btnCount
// Construct an anonymous instance of BtnCountListener (a named inner class).
3/3/2015 10:35 AM
25 of 52
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
The inner class can access the private variable tfCount and count of the outer class.
Since "this" is no longer a listener, we remove the "implements ActionListener" from this class' definition.
The
inner
class
is
compiled
into
AWTCount$BtnCountListener.class,
in
the
format
of
OuterClassName$InnerClassName.class.
3/3/2015 10:35 AM
26 of 52
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
import java.awt.*;
import java.awt.event.*;
// An AWT GUI program inherits from the top-level container java.awt.Frame
public class AWTCounterAnonymousInnerClass extends Frame {
// This class is NOT a ActionListener, hence, it does not implement ActionListener
// The event-handler actionPerformed() needs to access these private variables
private TextField tfCount;
private int count = 0;
/** Constructor to setup the GUI */
public AWTCounterAnonymousInnerClass () {
setLayout(new FlowLayout()); // "super" Frame sets to FlowLayout
add(new Label("Counter"));
// an anonymous instance of Label
tfCount = new TextField("0", 10);
tfCount.setEditable(false);
// read-only
add(tfCount);
// "super" Frame adds tfCount
Button btnCount = new Button("Count");
add(btnCount);
// "super" Frame adds btnCount
// Construct an anonymous instance of an anonymous class.
// btnCount adds this instance as a ActionListener.
btnCount.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
++count;
tfCount.setText(count + "");
}
});
setTitle("AWT Counter");
setSize(250, 100);
setVisible(true);
}
/** The entry main method */
public static void main(String[] args) {
new AWTCounterAnonymousInnerClass(); // Let the constructor do the job
}
}
3/3/2015 10:35 AM
27 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
tfCount.setText(count + "");
}
}
btnCount.addActionListener(new N());
// Or
N n = new N()
btnCount.addActionListener(n);
The above codes create an anonymous instance of an anonymous inner class, and pass it as the argument for a method. You can
also create a named instance of an anonymous inner class, for example,
// Create an named instance called drawPanel of an anonymous class extends JPanel
// Upcast to superclass
JPanel drawPanel = new JPanel() {
@Override
public void paintComponent(Graphics g) {
......
}
}
// same as
class N extends JPanel {
@Override
public void paintComponent(Graphics g) {
......
}
}
JPanel drawPanel = new N(); // upcast
1
2
import java.awt.*;
import java.awt.event.*;
3/3/2015 10:35 AM
28 of 52
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
5.4 Example 10: Using the Same Listener Instance for All the Buttons
If you use the same instance as the listener for the 3 buttons, you need to determine which button has fired the event. It is because all
the 3 buttons trigger the same event-handler method.
3/3/2015 10:35 AM
29 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
In the following example, we use the same instance of a named inner class as the listener for all the 3 buttons. The listener needs to
determine which button has fired the event. This can be accomplished via the ActionEvent's getActionCommonad() method, which
returns the button's label.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.awt.*;
import java.awt.event.*;
// An AWT GUI program inherits the top-level container java.awt.Frame
public class AWTCounter3Buttons1Listener extends Frame {
private TextField tfCount;
private int count = 0;
/** Constructor to setup the GUI */
public AWTCounter3Buttons1Listener () {
setLayout(new FlowLayout());
add(new Label("Counter"));
tfCount = new TextField("0", 10);
tfCount.setEditable(false);
add(tfCount);
// Create buttons
Button btnCountUp = new Button("Count Up");
add(btnCountUp);
Button btnCountDown = new Button("Count Down");
add(btnCountDown);
Button btnReset = new Button("Reset");
add(btnReset);
// Allocate an instance of inner class BtnListener.
BtnListener listener = new BtnListener();
// Use the same listener to all the 3 buttons.
btnCountUp.addActionListener(listener);
btnCountDown.addActionListener(listener);
btnReset.addActionListener(listener);
setTitle("AWT Counter");
setSize(400, 100);
setVisible(true);
}
/** The entry main method */
public static void main(String[] args) {
new AWTCounter3Buttons1Listener(); // Let the constructor do the job
}
/**
* BtnListener is a named inner class used as ActionEvent listener for the buttons.
*/
private class BtnListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// Need to determine which button has fired the event.
// getActionCommand() returns the button's label
String btnLabel = e.getActionCommand();
if (btnLabel.equals("Count Up")) {
++count;
} else if (btnLabel.equals("Count Down")) {
--count;
} else {
count = 0;
}
tfCount.setText(count + "");
}
}
}
3/3/2015 10:35 AM
30 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import java.awt.*;
import java.awt.event.*;
public class AWTCounter3ButtonsGetSource extends Frame {
private TextField tfCount;
private Button btnCountUp, btnCountDown, btnReset;
private int count = 0;
/** Constructor to setup the GUI */
public AWTCounter3ButtonsGetSource () {
setLayout(new FlowLayout());
add(new Label("Counter"));
tfCount = new TextField("0", 10);
tfCount.setEditable(false);
add(tfCount);
// Create buttons
btnCountUp = new Button("Count Up");
add(btnCountUp);
btnCountDown = new Button("Count Down");
add(btnCountDown);
btnReset = new Button("Reset");
add(btnReset);
// Allocate an instance of inner class BtnListener.
BtnListener listener = new BtnListener();
// Use the same listener to all the 3 buttons.
btnCountUp.addActionListener(listener);
btnCountDown.addActionListener(listener);
btnReset.addActionListener(listener);
setTitle("AWT Counter");
setSize(400, 100);
setVisible(true);
}
/** The entry main method */
public static void main(String[] args) {
new AWTCounter3ButtonsGetSource(); // Let the constructor do the job
}
/**
* BtnListener is a named inner class used as ActionEvent listener for the buttons.
*/
private class BtnListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// Need to determine which button has fired the event.
Button source = (Button)e.getSource();
// Get a reference of the source that has fired the event.
// getSource() returns a java.lang.Object. Downcast back to Button.
if (source == btnCountUp) {
++count;
} else if (source == btnCountDown) {
--count;
} else {
count = 0;
}
tfCount.setText(count + "");
}
}
}
3/3/2015 10:35 AM
31 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
3/3/2015 10:35 AM
32 of 52
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
Constructing an inner
Hi from inner class
Constructing an inner
Inner class 2
Constructing an inner
Constructing an inner
Inner class 3
An inner class definition is merely a definition of a class. The outer class does not create an inner class instance, when it is instantiated.
Nonetheless, you could declare it as member of the outer class, as illustrated in the above example. In many situations, we declare the
inner class private. In this cases, the inner class can only be used (declare and construct) within the outer class.
You can set the inner class to private access. In this case, the inner class can only be accessed within the outer class, and not by other
classes.
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 static members are associated with the class, instead of instances.
1
2
3
3/3/2015 10:35 AM
33 of 52
4
5
6
7
8
9
10
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
// A "static" nested class, like other "static" members, can be accessed via
// the Classname.membername
MyOuterClassWithStaticNestedClass.MyStaticNestedClass aNestedInner =
new MyOuterClassWithStaticNestedClass.MyStaticNestedClass("Hi from inner class");
aNestedInner.printMessage();
}
}
As
seen
from
the
example,
static
nested
class
is
really
like
top-level
class
with
modified
name
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
3/3/2015 10:35 AM
34 of 52
39
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
outer class
{
the method
= "Hello from method";
Thread thread = new Thread() { // create an instance of an anonymous inner class that extends Thread class
@Override
public void run() {
System.out.println("Constructing an inner class instance: " + msgOuter);
// can access private member variable of outer class
System.out.println("Accessing final variable of the method: " + msgMethod);
// can access final variable of the method
System.out.println("Hi, from inner class!");
}
};
thread.start();
}
// Test main() method
public static void main(String[] args) {
// Create an instance of the outer class and invoke the method.
new MyOuterClassWithAnonymousInnerClass().doSomething();
}
}
Clearly, you can only create one instance for each anonymous inner class.
3/3/2015 10:35 AM
35 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
// abstract methods
abstract public double getX();
abstract public double getY();
abstract public void setLocation(double x, double y);
public double distance(double x, double y) { ... }
public double distance(Point2D p) { ... }
public static double distance(double x1, double y1, double x2, double y2) { ... }
......
public static class Double extends Point2D {
public double x;
public double y;
public Double(double x, double y) { ... }
@Override public double getX() { return x; }
@Override public double getY() { return y; }
@Override public void setLocation(double x, double y) { ... }
......
}
public static class Float extends Point2D {
public float x;
public float y;
public Double(float x, float y) { ... }
@Override public double getX() { ... }
@Override public double getY() { ... }
@Override public void setLocation(double x, double y) { ... }
public void setLocation(float x, float y) { ... }
......
}
}
package java.awt.geom;
public class Point extends Point2D {
public int x;
public int y;
public Point(int x, int y) { ... }
@Override public double getX() { return x; }
@Override public double getY() { return y; }
@Override public void setLocation(double x, double y) { ... }
......
}
Point2D.Double and Point2D.Float are public static classes. In other words, they can be used directly without instantiating the
outer class, just like any static variable or method (which can be referenced directly via the classname, e.g., Math.PI, Math.sqrt()
and Integer.parseInt()). Since they are subclass of Point2D, they can be upcast to Point2D.
Point2D.Double p1 = new Point2D.Double(1.1, 2.2);
3/3/2015 10:35 AM
36 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
Note: These classes were designed before the introduction of generic in JDK 1.5, which supports the passing of type as argument.
6.5 "Cannot refer to a non-final variable inside an inner class defined in a different
method"
Java specification 8.1.3: "Any local variable, formal method parameter or exception handler parameter used but not declared in an
inner class must be declared final."
By allowing inner class to access non-final local variables inside a method, the local variable could be modified by the inner class, and
causes a strange side-effect.
Solution:
1. Declare the variable final if permissible.
2. Declare the variable outside the method, e.g., as member variables of the class, instead of a local variable within a method. Both
the method and the inner class could access the variable.
3. Use a wrapper class to wrap the variable inside a class. Declare the instance final.
import java.awt.*;
import java.awt.event.*;
// An AWT GUI program inherits the top-level container java.awt.Frame
3/3/2015 10:35 AM
37 of 52
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
An adapter class called WindowAdapter is therefore provided, which implements the WindowListener interface and provides default
implementations to all the 7 abstract methods. You can then derive a subclass from WindowAdapter and override only methods of
interest and leave the rest to their default implementation. For example,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.awt.*;
import java.awt.event.*;
// An AWT GUI program inherits the top-level container java.awt.Frame
public class WindowEventDemoAdapter extends Frame {
private TextField tfCount;
private int count = 0;
/** Constructor to setup the GUI */
public WindowEventDemoAdapter () {
setLayout(new FlowLayout());
add(new Label("Counter"));
tfCount = new TextField("0", 10);
tfCount.setEditable(false);
3/3/2015 10:35 AM
38 of 52
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
add(tfCount);
Button btnCount = new Button("Count");
add(btnCount);
btnCount.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
++count;
tfCount.setText(count + "");
}
});
// Allocate an anonymous instance of an anonymous inner class
// that extends WindowAdapter.
// "this" Frame adds the instance as WindowEvent listener.
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0); // Terminate the program
}
});
setTitle("WindowEvent Demo");
setSize(250, 100);
setVisible(true);
}
/** The entry main method */
public static void main(String[] args) {
new WindowEventDemoAdapter();
// Let the constructor do the job
}
}
Container's setLayout()
A container has a setLayout() method to set its layout manager:
// java.awt.Container
public void setLayout(LayoutManager mgr)
To set up the layout of a Container (such as Frame, JFrame, Panel, or JPanel), you have to:
1. Construct an instance of the chosen layout object, via new and constructor, e.g., new FlowLayout())
2. Invoke the setLayout() method of the Container, with the layout object created as the argument;
3. Place the GUI components into the Container using the add() method in the correct order; or into the correct zones.
For example,
// Allocate a Panel (container)
3/3/2015 10:35 AM
39 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
Container's getLayout()
You can get the current layout via Container's getLayout().
Panel awtPanel = new Panel();
System.out.println(awtPanel.getLayout());
// java.awt.FlowLayout[hgap=5,vgap=5,align=center]
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.awt.*;
import java.awt.event.*;
// An AWT GUI program inherits the top-level container java.awt.Frame
public class AWTFlowLayoutDemo extends Frame {
private Button btn1, btn2, btn3, btn4, btn5, btn6;
/** Constructor to setup GUI components */
public AWTFlowLayoutDemo () {
setLayout(new FlowLayout());
// "this" Frame sets layout to FlowLayout, which arranges the components
// from left-to-right, and flow from top-to-bottom.
btn1 = new Button("Button 1");
3/3/2015 10:35 AM
40 of 52
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
add(btn1);
btn2 = new
add(btn2);
btn3 = new
add(btn3);
btn4 = new
add(btn4);
btn5 = new
add(btn5);
btn6 = new
add(btn6);
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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-tobottom
manner
in
the
order
aContainer.add(aComponent)).
they
are
added
(via
method
Constructors
public GridLayout(int rows, int columns);
public GridLayout(int rows, int columns, int hgap, int vgap);
// By default: rows=1, cols=0, hgap=0, vgap=0
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.awt.*;
import java.awt.event.*;
// An AWT GUI program inherits the top-level container java.awt.Frame
public class AWTGridLayoutDemo extends Frame {
private Button btn1, btn2, btn3, btn4, btn5, btn6;
/** Constructor to setup GUI components */
public AWTGridLayoutDemo () {
setLayout(new GridLayout(3, 2, 3, 3));
// "this" Frame sets layout to 3x2 GridLayout, horizontal and verical gaps of 3 pixels
// The components are added from left-to-right, top-to-bottom
btn1 = new Button("Button 1");
add(btn1);
btn2 = new Button("This is Button 2");
add(btn2);
btn3 = new Button("3");
add(btn3);
btn4 = new Button("Another Button 4");
add(btn4);
btn5 = new Button("Button 5");
add(btn5);
btn6 = new Button("One More Button 6");
add(btn6);
3/3/2015 10:35 AM
41 of 52
26
27
28
29
30
31
32
33
34
35
36
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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, the cols value is ignored. The actual cols is determined by the actual number of components and rows.
8.3 BorderLayout
In java.awt.BorderLayout, the container is divided into 5 zones: EAST, WEST, SOUTH,
NORTH,
and
CENTER.
Components
are
added
using
method
BorderLayout.WEST
(or
BorderLayout.SOUTH
The
(or
PAGE_END),
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.awt.*;
import java.awt.event.*;
// An AWT GUI program inherits the top-level container java.awt.Frame
public class AWTBorderLayoutDemo extends Frame {
private Button btnNorth, btnSouth, btnCenter, btnEast, btnWest;
/** Constructor to setup GUI components */
public AWTBorderLayoutDemo () {
setLayout(new BorderLayout(3, 3));
// "this" Frame sets layout to BorderLayout,
// horizontal and vertical gaps of 3 pixels
// The components are added to the specified zone
btnNorth = new Button("NORTH");
add(btnNorth, BorderLayout.NORTH);
btnSouth = new Button("SOUTH");
add(btnSouth, BorderLayout.SOUTH);
btnCenter = new Button("CENTER");
add(btnCenter, BorderLayout.CENTER);
btnEast = new Button("EAST");
add(btnEast, BorderLayout.EAST);
btnWest = new Button("WEST");
add(btnWest, BorderLayout.WEST);
setTitle("BorderLayout Demo"); // "this" Frame sets title
setSize(280, 150);
// "this" Frame sets initial size
setVisible(true);
// "this" Frame shows
}
3/3/2015 10:35 AM
42 of 52
30
31
32
33
34
35
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import java.awt.*;
import java.awt.event.*;
// An AWT GUI program inherits the top-level container java.awt.Frame
public class AWTPanelDemo extends Frame {
private Button[] btnNumbers = new Button[10]; // Array of 10 numeric buttons
private Button btnHash, btnStar;
private TextField tfDisplay;
/** Constructor to setup GUI components */
public AWTPanelDemo () {
// Set up display panel
Panel panelDisplay = new Panel(new FlowLayout());
tfDisplay = new TextField("0", 20);
panelDisplay.add(tfDisplay);
// Set up button panel
Panel panelButtons = new Panel(new GridLayout(4, 3));
btnNumbers[1] = new Button("1");
panelButtons.add(btnNumbers[1]);
btnNumbers[2] = new Button("2");
panelButtons.add(btnNumbers[2]);
btnNumbers[3] = new Button("3");
panelButtons.add(btnNumbers[3]);
btnNumbers[4] = new Button("4");
panelButtons.add(btnNumbers[4]);
btnNumbers[5] = new Button("5");
panelButtons.add(btnNumbers[5]);
btnNumbers[6] = new Button("6");
panelButtons.add(btnNumbers[6]);
btnNumbers[7] = new Button("7");
panelButtons.add(btnNumbers[7]);
btnNumbers[8] = new Button("8");
panelButtons.add(btnNumbers[8]);
btnNumbers[9] = new Button("9");
panelButtons.add(btnNumbers[9]);
// Can use a loop for the above statements!
btnStar = new Button("*");
panelButtons.add(btnStar);
btnNumbers[0] = new Button("0");
panelButtons.add(btnNumbers[0]);
btnHash = new Button("#");
panelButtons.add(btnHash);
setLayout(new BorderLayout());
3/3/2015 10:35 AM
43 of 52
46
47
48
49
50
51
52
53
54
55
56
57
58
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
add(panelDisplay, BorderLayout.NORTH);
add(panelButtons, BorderLayout.CENTER);
setTitle("BorderLayout Demo"); // "this" Frame sets title
setSize(200, 200);
// "this" Frame sets initial size
setVisible(true);
// "this" Frame shows
}
/** The entry main() method */
public static void main(String[] args) {
new AWTPanelDemo(); // Let the constructor do the job
}
}
8.5 BoxLayout
BoxLayout arrange components in a single row or column. It respects components' requests on the minimum sizes.
[TODO] Example and diagram
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
contain Containers. Consequently, a Container can contain Containers and Components.
The Gof calls this recursive composition class design "composite design pattern", which is illustrated as follows:
3/3/2015 10:35 AM
44 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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.
3/3/2015 10:35 AM
45 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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.
4. Swing supports mouse-less operation, i.e., it can operate entirely using keyboard.
5. Swing components support "tool-tips".
6. Swing components are JavaBeans a Component-based Model used in Visual Programming (like Visual Basic). You can
drag-and-drop a Swing component into a "design form" using a "GUI builder" and double-click to attach an event handler.
7. Swing application uses AWT event-handling classes (in package java.awt.event). Swing added some new classes in package
javax.swing.event, but they are not frequently used.
8. Swing application uses AWT's layout manager (such as FlowLayout and BorderLayout in package java.awt). It added new
layout managers, such as Springs, Struts, and BoxLayout (in package javax.swing).
3/3/2015 10:35 AM
46 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
9. Swing implements double-buffering and automatic repaint batching for smoother screen repaint.
10. Swing introduces JLayeredPane and JInternalFrame for creating Multiple Document Interface (MDI) applications.
11. Swing supports floating toolbars (in JToolBar), splitter control, "undo".
12. Others - check the Swing website.
Swing's Components
Compared with the AWT classes (in package java.awt), Swing component classes (in package javax.swing) begin with a prefix "J",
e.g., JButton, JTextField, JLabel, JPanel, JFrame, or JApplet.
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.
used
for
the
applet's
display-area
3/3/2015 10:35 AM
47 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
components.
2. set the content-pane to a JPanel (the main panel created in your application which holds all your GUI components) via JFrame's
setContentPane().
public class TestSetContentPane extends JFrame {
// Constructor
public TestSetContentPane() {
// The "main" JPanel holds all the GUI components
JPanel mainPanel = new JPanel(new FlowLayout());
mainPanel.add(new JLabel("Hello, world!"));
mainPanel.add(new JButton("Button"));
// Set the content-pane of this JFrame to the main JPanel
this.setContentPane(mainPanel);
......
}
.......
}
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
package javax.swing.event) but they are not frequently used.
3/3/2015 10:35 AM
48 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
4. Run the constructor in the Event Dispatcher Thread (instead of Main thread) for thread safety, as shown in the following program
template.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// A Swing GUI application inherits from top-level container javax.swing.JFrame
public class ...... extends JFrame {
// private variables
// ......
/** Constructor to setup the GUI components */
public ......() {
Container cp = this.getContentPane();
// Content-pane sets layout
cp.setLayout(new ....Layout());
// Allocate the GUI components
// .....
// Content-pane adds components
cp.add(....);
// Source object adds listener
// .....
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Exit the program when the close-window button clicked
setTitle("......"); // "this" JFrame sets title
setSize(300, 150);
// "this" JFrame sets initial size (or pack())
setVisible(true);
// show it
}
/** The entry main() method */
public static void main(String[] args) {
// Run GUI codes in Event-Dispatching thread for thread-safety
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ......(); // Let the constructor do the job
}
});
}
}
1
2
3
4
5
import java.awt.*;
// Using AWT containers and components
import java.awt.event.*; // Using AWT events and listener interfaces
import javax.swing.*;
// Using Swing components and containers
// A Swing GUI application inherits from top-level container javax.swing.JFrame
3/3/2015 10:35 AM
49 of 52
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
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(); //
cp.setLayout(new FlowLayout()); //
cp.add(new JLabel("Counter"));
//
......
cp.add(tfCount);
// content-pane
......
cp.add(btnCount);
// content-pane
You can also use the JFrame's setContentPane() method to directly set the content-pane to a JPanel (or a JComponent). For
example,
JPanel displayPanel = new JPanel();
this.setContentPane(displayPanel);
// "this" JFrame sets its content-pane to a JPanel directly
.....
3/3/2015 10:35 AM
50 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
JFrame's setDefaultCloseOperation()
Instead of writing a WindowEvent listener with a windowClosing() handler to process the "close-window" button, JFrame provides a
method called setDefaultCloseOperation() to sets the default operation when the user initiates a "close" on this frame. Typically,
we choose the option JFrame.EXIT_ON_CLOSE, which terminates the application via a System.exit().
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
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.
To run the constructor on the event-dispatching thread, invoke static method SwingUtilities.invokeLater() to asynchronously
queue the constructor on the event-dispatching thread. The codes will be run after all pending events have been processed. For
example,
public static void main(String[] args) {
// Run the GUI codes in the Event-dispatching thread for thread-safety
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new SwingCounter(); // Let the constructor do the job
}
});
}
Warning Message "The serialization class does not declare a static final serialVersionUID field of type
long"
This warning message is triggered because java.awt.Frame (via its superclass java.awt.Component) implements the
java.io.Serializable interface. This interface enables the object to be written out to an output stream serially (via method
writeObject()); and read back into the program (via method readObject()). The serialization runtime uses a number (called
serialVersionUID) to ensure that the object read into the program is compatible with the class definition, and not belonging to
another version.
You have these options:
1. Simply ignore this warning message. If a serializable class does not explicitly declare a serialVersionUID, then the
serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class.
2. Add a serialVersionUID (Recommended), e.g.
3/3/2015 10:35 AM
51 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
// version 1
3. Suppress this particular warning via annotation @SuppressWarmomgs (in package java.lang) (JDK 1.5):
@SuppressWarnings("serial")
public class MyFrame extends JFrame { ...... }
import java.awt.*;
// Using AWT containers and components
import java.awt.event.*; // Using AWT events and listener interfaces
import javax.swing.*;
// Using Swing components and containers
// A Swing GUI application inherits the top-level container javax.swing.JFrame
public class SwingAccumulator extends JFrame {
private JTextField tfInput, tfOutput;
private int numberIn;
// input number
private int sum = 0;
// accumulated sum, init to 0
/** Constructor to setup the GUI */
public SwingAccumulator() {
// Retrieve the content-pane of the top-level container JFrame
// All operations done on the content-pane
Container cp = getContentPane();
cp.setLayout(new GridLayout(2, 2, 5, 5));
add(new JLabel("Enter an Integer: "));
tfInput = new JTextField(10);
add(tfInput);
add(new JLabel("The Accumulated Sum is: "));
tfOutput = new JTextField(10);
tfOutput.setEditable(false); // read-only
add(tfOutput);
// Allocate an anonymous instance of an anonymous inner class that
// implements ActionListener as ActionEvent listener
tfInput.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Get the String entered into the input TextField, convert to int
numberIn = Integer.parseInt(tfInput.getText());
sum += numberIn;
// accumulate numbers entered into sum
tfInput.setText(""); // clear input TextField
tfOutput.setText(sum + ""); // display sum on the output TextField
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Exit program if close-window button clicked
setTitle("Swing Accumulator"); // "this" Frame sets title
setSize(350, 120); // "this" Frame sets initial size
setVisible(true);
// "this" Frame shows
}
/** The entry main() method */
public static void main(String[] args) {
// Run the GUI construction in the Event-Dispatching thread for thread-safety
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new SwingAccumulator(); // Let the constructor do the job
}
});
}
}
3/3/2015 10:35 AM
52 of 52
https://www3.ntu.edu.sg/home/ehchua/programming/java/J4a_GUI.html
11.1 NetBeans
For using NetBeans GUI Builder, read my "Writing Java GUI (AWT/Swing) Application in NetBeans"; or Swing Tutorial's "Learning Swing
with the NetBeans IDE".
11.2 Eclipse
For using Eclipse GUI Builder, read "Writing Swing Applications using Eclipse GUI Builder".
Feedback, comments, corrections, and errata can be sent to Chua Hock-Chuan ([email protected]) | HOME
3/3/2015 10:35 AM