Java Gui
Java Gui
Interface (GUI)
1. Introduction
So far, we have covered the basic programming constructs (such as variables, data types, decision,
loop, array and method) and introduced the important concept of Object-Oriented Programming
(OOP). As discussed, OOP permits higher level of abstraction than traditional Procedural-Oriented
Languages (such as C). You can create high-level abstract data types called classes to mimic real-life
things. These classes are self-contained and are reusable.
In this material, 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
(and re-inventing the wheels) is mission impossible! These graphics classes, developed by expert
programmers, are highly complex and involve many advanced design patterns. However, re-using
them are not so difficult, if you follow the API documentation, samples and templates provided.
There are current three sets of Java APIs for graphics programming: AWT
(Abstract Windowing Toolkit), Swing and JavaFX.
1. AWT API was introduced in JDK 1.0. Most of the AWT UI components have become
obsolete and should be replaced by newer Swing UI 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 has been integrated into core Java since JDK 1.2.
3. The latest JavaFX, which was integrated into JDK 8, was meant to replace Swing. JavaFX
was moved out from the JDK in JDK 11, but still available as a separate module.
Other than AWT/Swing/JavaFX graphics APIs provided in JDK, other organizations/vendors 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), Java3D, and etc. Furthermore, developers have moved to use technologies such as
HTML5 as the basis of webapps.
• r
A Frame provides the "main window" for your GUI application. It has a title bar (containing
an icon, a title, the minimize, 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 {
•
• // private variables
• ......
•
• // Constructor to setup the GUI components and event handlers
• public MyGUIProgram() { ...... }
•
• // The entry main() method
• public static void main(String[] args) {
• // Invoke the constructor (to setup the GUI) by allocating an instance
• new MyGUIProgram();
• }
}
• An AWT Dialog is a "pop-up window"
used for interacting with the users. A Dialog has a title-bar (containing an icon, a title and
a close button) and a content display area, as illustrated.
• An AWT Applet (in package java.applet) is the top-level container for an applet, which
is a Java program running inside a browser. Applet is no longer supported in most of the
browsers.
Secondary Containers: Panel and ScrollPane
Secondary containers are placed inside a top-level container or another secondary container. AWT
provides these secondary containers:
• Panel: a rectangular box 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:
As illustrated, a Container has a LayoutManager to layout the components in a certain pattern, e.g.,
flow, grid.
2.4 AWT Component Classes
AWT provides many ready-made and reusable GUI components in package java.awt. The frequently-
used are: Button, TextField, Label, Checkbox, CheckboxGroup (radio buttons), List, and Choice, as
illustrated below.
A java.awt.Label provides a descriptive text string. Take note that System.out.println() prints to
the system console, NOT to the graphics screen. You could use a Label to label another component
(such as text field) to provide a text description.
Check the JDK API specification for java.awt.Label.
Constructors
public Label(String strLabel, int alignment); // Construct a Label with the given text
String, of the text alignment
public Label(String strLabel); // Construct a Label with the given text
String
public Label(); // Construct an initially empty Label
The Label class has three constructors:
1. The first constructor constructs a Label object with the given text string in the given
alignment. Note that three static constants Label.LEFT, Label.RIGHT,
and Label.CENTER are defined in the class for you to specify the alignment (rather than
asking you to memorize arbitrary integer values).
2. The second constructor constructs a Label object with the given text string in default of
left-aligned.
3. The third constructor constructs a Label object with an initially empty string. You could
set the label text via the setText() method later.
Constants (final static fields)
public static final LEFT; // Label.LEFT
public static final RIGHT; // Label.RIGHT
public static final CENTER; // Label.CENTER
These three constants are defined for specifying the alignment of the Label's text, as used in the above
constructor.
Public Methods
// Examples
public String getText();
public void setText(String strLabel);
public int getAlignment();
public void setAlignment(int alignment); // Label.LEFT, Label.RIGHT, Label.CENTER
The getText() and setText() methods can be used to read and modify the Label's text. Similarly,
the getAlignment() and setAlignment() methods can be used to retrieve and modify the alignment
of the text.
Constructing a Component and Adding the Component into a Container
Three steps are necessary to create and place a GUI component:
1. Declare the component with an identifier (name);
2. Construct the component by invoking an appropriate constructor via the new operator;
3. Identify the container (such as Frame or Panel) designed to hold this component. The
container can then add this component onto itself
via aContainer.add(aComponent) method. Every container has
a add(Component) method. Take note that it is the container that actively and explicitly
adds a component onto itself, NOT the other way.
Example
Example
// Same as
Label xxx = new Label("Enter Name: ", Label.RIGHT)); // xxx assigned by compiler
add(xxx);
A java.awt.Button is a GUI component that triggers a certain programmed action upon clicking.
Constructors
public Button(String btnLabel);
// 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
Let's assemble a few 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 shall display
count of 0 initially.
Each time you click the button, the counter's value increases by 1.
System.out.println(this);
//AWTCounter[frame0,93,0,300x100,invalid,hidden,layout=java.awt.FlowLayout,title=AWT
Counter,resizable,normal]
// name (assigned by compiler) is "frame0"; top-left (x,y) at (93,0); width/height
is 300x100 (via setSize());
System.out.println(lblCount);
//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 constructor)
System.out.println(tfCount);
//java.awt.TextField[textfield0,0,0,0x0,invalid,text=0,selection=0-0]
// name is "Textfield0"; text is "0" (assigned in constructor)
System.out.println(btnCount);
//java.awt.Button[button0,0,0,0x0,invalid,label=Count]
// name is "button0"; label text is "Count" (assigned in constructor)
setVisible(true); // "super" Frame shows
System.out.println(this);
//AWTCounter[frame0,93,0,300x100,invalid,layout=java.awt.FlowLayout,title=AWT
Counter,resizable,normal]
System.out.println(lblCount);
//java.awt.Label[label0,31,35,57x23,align=left,text=Counter]
System.out.println(tfCount);
//java.awt.TextField[textfield0,93,35,124x23,text=0,selection=0-0]
System.out.println(btnCount);
//java.awt.Button[button0,222,35,46x23,label=Count]
In this example, the top-level container is again the typical java.awt.Frame. It 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 GridLayout of 2 rows 2 columns.
The program shall accumulate the number entered into the input TextField and display the sum in
the output TextField.
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 (customized) from the top-level container
5// java.awt.Frame
6public class AWTAccumulator extends Frame {
7 //private Label lblInput; // Declare input Label (to use anonymous)
8 //private Label lblOutput; // Declare output Label (to use anonymous)
9 private TextField tfInput; // Declare input TextField
10 private TextField tfOutput; // Declare output TextField
11 private int sum = 0; // Accumulated sum, init to 0
12
13 // Constructor to setup the GUI components and event handlers
14 public AWTAccumulator() {
15 setLayout(new GridLayout(2, 2));
16 // "super" Frame (Container) sets layout to GridLayout of 2 rows 2 columns.
17
18 add(new Label("Enter an Integer: ")); // "super" Frame adds an anonymous Label
19
20 tfInput = new TextField(10); // Construct TextField
21 add(tfInput); // "super" Frame adds TextField
22
23 tfInput.addActionListener(new TFInputListener());
24 // "tfInput" is the source object that fires an ActionEvent upon entered.
25 // The source add an anonymous instance of TFInputListener as an ActionEvent
26 // listener, which provides an ActionEvent handler called actionPerformed().
27 // Hitting "enter" on tfInput invokes actionPerformed().
28
29 add(new Label("The Accumulated Sum is: ")); // "super" Frame adds an anonymous Label
30
31 tfOutput = new TextField(10); // allocate TextField
32 tfOutput.setEditable(false); // read-only
33 add(tfOutput); // "super" Frame adds TextField
34
35 setTitle("AWT Accumulator"); // "super" Frame sets title
36 setSize(350, 120); // "super" Frame sets initial window size
37 setVisible(true); // "super" Frame shows
38 }
39
40 // The entry main() method
41 public static void main(String[] args) {
42 // Invoke the constructor to setup the GUI, by allocating an anonymous instance
43 new AWTAccumulator();
44 }
45
46 // Define an inner class to handle the input TextField.
47 // An ActionEvent listener must implement ActionListener interface.
48 private class TFInputListener implements ActionListener {
49 // ActionEvent handler - Called back upon hitting "enter" key on TextField
50 @Override
51 public void actionPerformed(ActionEvent evt) {
52 // Get the String entered into the TextField tfInput, convert to int
53 int numberIn = Integer.parseInt(tfInput.getText());
54 sum += numberIn; // Accumulate numbers entered into sum
55 tfInput.setText(""); // Clear input TextField
56 tfOutput.setText(sum + ""); // Display sum on the output TextField
57 // convert int to String
58 }
59 }
60}
Dissecting the AWTAccumulator.java
1. An AWT GUI program extends from java.awt.Frame (Line 6) - the top-level window
container.
2. In the constructor (Line 14), we constructs 4 components - 2
anonymous java.awt.Labels and 2 java.awt.TextFields. The Frame adds the
components, in GridLayout.
3. tfInput (TextField) is the source object, which fires an ActionEvent upon hitting the
Enter key. tfInput adds an anonymous instance of TFInputListener as
an ActionEvent handler (Line 23). The listener class needs to
implement ActionListener interface and provides implementation to
method actionPerformed(). Whenever an user hits Enter on the tfInput (TextField),
the actionPerformed() will be called back.
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 like Visual Basic.
In event-driven programming, a piece of event-handling codes is executed (or called back by the
graphics subsystem) when an event was fired in response to an user input (such as clicking a mouse
button or hitting the ENTER key in a text field).
Callback Methods
In the above examples, the method actionPerformed() is known as a callback method. In other
words, you never invoke actionPerformed() in your codes explicitly.
The actionPerformed() is called back by the graphics subsystem under certain circumstances in
response to certain user actions.
JavaScript can attach a Callback method to an Event Directly
In some languages, you can directly attach a method (or function) to an event (such as mouse-click).
For example, the following JavaScript code (called JSCounter.html) implement a counter similar to
the AWTCounter, with a text label, text field and button:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript Counter</title></head>
<body>
<form>
Count: <input id="tfCount" type="text" value="0">
<input id="btnCount" type="button" value="Hello"
onclick=myBtnOnClick() onmouseover=myBtnMouseOver() >
</form>
<script>
function myBtnOnClick() { tfCount.value++; }
function myBtnMouseOver() { btnCount.value = "Count Up"; }
function myBtnMouseOut() { btnCount.value = "Click Me"; }
btnCount.onmouseout = myBtnMouseOut; // assign a function to a variable
</script>
</body>
</html>
In Java, we CANNOT attach a method to a source object directly, as method is not a first-class object
in Java. For example, a Java method cannot accept methods as its arguments and it cannot return a
method; you cannot assign a method to a variable, etc. (JavaScript and C language CAN!).
Source, Event and Listener Objects
The AWT's event-handling classes are kept in package java.awt.event.
Three kinds of 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, the source
object creates an event object to capture the action (e.g., mouse-click x and y, texts entered, etc).
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 event handler of the listener(s).
To express interest for a certain source's event, the listener(s) must be registered with the source. In
other words, the listener(s) "subscribes" to a source's event, and the source "publishes" the event to
all its subscribers upon activation. This is known as subscribe-publish or observable-observer design
pattern.
The sequence of steps is illustrated above:
1. The source object registers its listener(s) for a certain type of event.
A source fires an event when triggered. For example, clicking a Button fires
an ActionEvent, clicking a mouse button fires MouseEvent, typing a key fires KeyEvent,
and etc.
How the source and listener understand each other? The answer is via an agreed-upon
interface. For example, if a source is capable of firing an event
called XxxEvent (e.g., ActionEvent). Firstly, we need to declare an interface
called XxxListener (e.g., ActionListener) containing the names of the handler
methods (recall that an interface contains only abstract methods without
implementation). For example, the ActionListener interface is declared as follows:
// An ActionListener interface, which declares the signature of the
handlers
public interface ActionListener {
public void actionPerformed(ActionEvent evt);
}
Secondly, all XxxEvent listeners 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 listener(s)
can response to these events appropriately. For example,
// An example of MouseListener, which provides implementation to the event
handler methods
class MyActionListener implement ActionListener {
@Override
public void actionPerformed(ActionEvent evt) {
System.out.println("ActionEvent detected!");
}
}
Thirdly, in the source, we need to maintain a list of XxxEvent listener object(s), and
define two methods: addXxxListener() and removeXxxListener() to add and remove
a XxxEvent listener from this list. For the ActionEvent, the signature of the methods
are:
Take note that the addXxxListenser() takes a XxxListener object as its sole
parameter. In other words, it can only add objects of the type XxxListener, and its sub-
type. Since XxxListener is an interface, you cannot create instance of XxxListener,
but need to create instance of a subclass implementing the XxxListener interface.
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(XxxListener lis) method.
2. The source is triggered by a user.
3. The source create a XxxEvent object, which encapsulates the necessary information
about the activation. For example, the (x, y) position of the mouse pointer, the text
entered, etc.
4. Finally, for each of the XxxEvent listeners in the listener list, the source invokes the
appropriate handler on the listener(s), which provides the programmed response.
In summary, triggering a source fires an event to all its registered listeners, and invoke an appropriate
handler of the listener.
3.1 Revisit Example
1 AWTCounter: ActionEvent and ActionListener Interface
Clicking a Button (or hitting the "Enter" key on a TextField) fires an ActionEvent to all
its ActionEvent listener(s). An ActionEvent listener must implement the ActionListener interface,
which declares one abstract method called actionPerformed() as follow:
btnCount.addActionListener(listener);
A WindowEvent is fired (to all its WindowEvent listeners) 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 of WindowEvent 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 evt)
// 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 evt)
// Called-back the first time a window is made visible.
public void windowClosed(WindowEvent evt)
// Called-back when a window has been closed as the result of calling dispose on
the window.
public void windowActivated(WindowEvent evt)
// Called-back when the Window is set to be the active Window.
public void windowDeactivated(WindowEvent evt)
// Called-back when a Window is no longer the active Window.
public void windowIconified(WindowEvent evt)
// Called-back when a window is changed from a normal to a minimized state.
public void windowDeiconified(WindowEvent evt)
// 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 classes and listener
3interfaces
4
5// An AWT GUI program inherits the top-level container java.awt.Frame
6public class WindowEventDemo extends Frame {
7
8 private TextField tfCount; // Declare a TextField component
9 private Button btnCount; // Declare a Button component
10 private int count = 0; // Counter's value
11
12 // Constructor to setup the GUI components and event handlers
13 public WindowEventDemo() {
14 setLayout(new FlowLayout()); // "super" Frame sets to FlowLayout
15
16 add(new Label("Counter")); // "super" Frame adds an anonymous Label
17
18 tfCount = new TextField("0", 10); // Construct the TextField
19 tfCount.setEditable(false); // read-only
20 add(tfCount); // "super" Frame adds TextField
21
22 btnCount = new Button("Count"); // Construct the Button
23 add(btnCount); // "super" Frame adds Button
24
25 btnCount.addActionListener(new BtnCountListener());
26 // btnCount (source object) fires ActionEvent upon clicking
27 // btnCount adds an anonymous instance of BtnCountListener
28 // as an ActionEvent listener
29
30 addWindowListener(new MyWindowListener());
31 // "super" Frame (source object) fires WindowEvent.
32 // "super" Frame adds an anonymous instance of MyWindowListener
33 // as a WindowEvent listener.
34
35 setTitle("WindowEvent Demo"); // "super" Frame sets title
36 setSize(300, 100); // "super" Frame sets initial size
37 setVisible(true); // "super" Frame shows
38 }
39
40 // The entry main() method
41 public static void main(String[] args) {
42 new WindowEventDemo(); // Let the construct do the job
43 }
44
45 // Define an inner class to handle ActionEvent of btnCount
46 private class BtnCountListener implements ActionListener {
47 @Override
48 public void actionPerformed(ActionEvent evt) {
49 ++count;
50 tfCount.setText(count + "");
51 }
52 }
53
54 // Define an inner class to handle WindowEvent of this Frame
55 private class MyWindowListener implements WindowListener {
56 // Called back upon clicking close-window button
57 @Override
58 public void windowClosing(WindowEvent evt) {
59 System.exit(0); // Terminate the program
60 }
61
62 // Not Used, BUT need to provide an empty body to compile.
63 @Override public void windowOpened(WindowEvent evt) { }
64 @Override public void windowClosed(WindowEvent evt) { }
65 // For Debugging
66 @Override public void windowIconified(WindowEvent evt) {
67System.out.println("Window Iconified"); }
68 @Override public void windowDeiconified(WindowEvent evt) {
69System.out.println("Window Deiconified"); }
70 @Override public void windowActivated(WindowEvent evt) {
System.out.println("Window Activated"); }
@Override public void windowDeactivated(WindowEvent evt) {
System.out.println("Window Deactivated"); }
}
}
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 the super Frame as the source object.
2. The Frame fires the WindowEvent to all its registered WindowEvent listener(s).
3. In Line 53-69, we define an inner class called MyWindowListener as
the WindowEvent listener. It is required to implement the WindowListener interface,
which declares 7 abstract
methods: windowOpened(), windowClosed(), windowClosing(), windowActivated(), w
indowDeactivated(), windowIconified() and windowDeiconified().
4. We register an anonymous instance of MyWindowListener as the WindowEvent listener
to the source Frame via method addWindowListener(new MyWindowListener()).
5. We override the windowClosing() handler to terminate the program
using System.exit(0). We ignore the other 6 handlers, but required to provide an
empty body for compilation.
1import java.awt.*;
2import java.awt.event.*;
3
4public class MouseEventDemo extends Frame {
5 private TextField tfMouseX; // to display mouse-click-x
6 private TextField tfMouseY; // to display mouse-click-y
7
8 // Constructor - Setup the UI components and event handlers
9 public MouseEventDemo() {
10 setLayout(new FlowLayout()); // "super" frame sets its layout to FlowLayout
11
12 // Label (anonymous)
13 add(new Label("X-Click: ")); // "super" frame adds Label component
14
15 // TextField
16 tfMouseX = new TextField(10); // 10 columns
17 tfMouseX.setEditable(false); // read-only
18 add(tfMouseX); // "super" frame adds TextField component
19
20 // Label (anonymous)
21 add(new Label("Y-Click: ")); // "super" frame adds Label component
22
23 // TextField
24 tfMouseY = new TextField(10);
25 tfMouseY.setEditable(false); // read-only
26 add(tfMouseY); // "super" frame adds TextField component
27
28 addMouseListener(new MyMouseListener());
29 // "super" frame (source) fires the MouseEvent.
30 // "super" frame adds an anonymous instance of MyMouseListener
31 // as a MouseEvent listener.
32
33 setTitle("MouseEvent Demo"); // "super" Frame sets title
34 setSize(350, 100); // "super" Frame sets initial size
35 setVisible(true); // "super" Frame shows
36 }
37
38 public static void main(String[] args) {
39 new MouseEventDemo(); // Let the constructor do the job
40 }
41
42 // Define an inner class to handle MouseEvent
43 private class MyMouseListener implements MouseListener {
44 // Called back upon mouse clicked
45 @Override
46 public void mouseClicked(MouseEvent evt) {
47 tfMouseX.setText(evt.getX() + "");
48 tfMouseY.setText(evt.getY() + "");
49 }
50
51 // Not used - need to provide an empty body to compile.
52 @Override public void mousePressed(MouseEvent evt) { }
53 @Override public void mouseReleased(MouseEvent evt) { }
54 @Override public void mouseEntered(MouseEvent evt) { }
55 @Override public void mouseExited(MouseEvent evt) { }
56 }
57}
In this example, we setup a GUI with 4 components (two anonynous 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. In Line 42-56, we define an inner class called MyMouseListener as
the MouseEvent listener. It 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) coordinates 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).
4. We register an anonymous instance of MyMouseListener as the MouseEvent listener
to super Frame (source) via the method addMouseListener(new MyMouseListener()).
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 move and drag the mouse pointer at the source object. But you
need to use MouseMotionListener to handle the mouse-move and mouse-drag.
The MouseMotionListener interface declares the following two abstract methods:
public void mouseDragged(MouseEvent e)
// Called-back when a mouse-button is pressed on the source component and then
dragged.
public void mouseMoved(MouseEvent e)
// Called-back when the mouse-pointer has been moved onto the source component but
no buttons have been pushed.
1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits from the top-level container
5java.awt.Frame
6public class MouseMotionDemo extends Frame {
7
8 // To display the (x, y) of the mouse-clicked
9 private TextField tfMouseClickX;
10 private TextField tfMouseClickY;
11 // To display the (x, y) of the current mouse-pointer position
12 private TextField tfMousePositionX;
13 private TextField tfMousePositionY;
14
15 // Constructor to setup the GUI components and event handlers
16 public MouseMotionDemo() {
17 setLayout(new FlowLayout()); // "super" frame sets to FlowLayout
18
19 add(new Label("X-Click: "));
20 tfMouseClickX = new TextField(10);
21 tfMouseClickX.setEditable(false);
22 add(tfMouseClickX);
23 add(new Label("Y-Click: "));
24 tfMouseClickY = new TextField(10);
25 tfMouseClickY.setEditable(false);
26 add(tfMouseClickY);
27
28 add(new Label("X-Position: "));
29 tfMousePositionX = new TextField(10);
30 tfMousePositionX.setEditable(false);
31 add(tfMousePositionX);
32 add(new Label("Y-Position: "));
33 tfMousePositionY = new TextField(10);
34 tfMousePositionY.setEditable(false);
35 add(tfMousePositionY);
36
37 MyMouseListener listener = new MyMouseListener();
38 addMouseListener(listener);
39 addMouseMotionListener(listener);
40 // "super" frame (source) fires MouseEvent.
41 // "super" frame adds an instance of MyMouseListener
42 // as MouseListener and MouseMotionListener.
43
44 setTitle("MouseMotion Demo"); // "super" Frame sets title
45 setSize(400, 120); // "super" Frame sets initial size
46 setVisible(true); // "super" Frame shows
47 }
48
49 // The entry main() method
50 public static void main(String[] args) {
51 new MouseMotionDemo(); // Let the constructor do the job
52 }
53
54 // Define an inner class as both the MouseListener and
55MouseMotionListener
56 // A Java class can extend one superclass but implement many
57interfaces
58 private class MyMouseListener implements MouseListener,
59MouseMotionListener {
60 /* MouseListener handlers */
61 // Called back when a mouse-button has been clicked
62 @Override
63 public void mouseClicked(MouseEvent evt) {
64 tfMouseClickX.setText(evt.getX() + "");
65 tfMouseClickY.setText(evt.getY() + "");
66 }
67
68 // Not Used, but need to provide an empty body for compilation
69 @Override public void mousePressed(MouseEvent evt) { }
70 @Override public void mouseReleased(MouseEvent evt) { }
71 @Override public void mouseEntered(MouseEvent evt) { }
72 @Override public void mouseExited(MouseEvent evt) { }
73
74 /* MouseMotionEvent handlers */
75 // Called back when the mouse-pointer has been moved
76 @Override
77 public void mouseMoved(MouseEvent evt) {
78 tfMousePositionX.setText(evt.getX() + "");
79 tfMousePositionY.setText(evt.getY() + "");
80 }
81
// Not Used, but need to provide an empty body for compilation
@Override public void mouseDragged(MouseEvent evt) { }
}
}
In this example, we shall illustrate both the MouseListener and MouseMotionListener.
1. We identify the super Frame as the source, which fires the MouseEvent to its
registered MouseListener and MouseMotionListener.
2. In Line 53-80, we define an inner class called MyMouseListener as both
the MouseListener and MouseMotionListner.
3. We register an instance of MyMouseListener as the listener to super Frame via
method addMouseListener() and addMouseMotionListener().
4. The MouseMotionListener 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.
Try: Include a WindowListener to handle the close-window button.
3.6 Example 6: KeyEvent and KeyListener Interface
A KeyEvent is fired when you pressed, released, and typed (pressed followed by released) a key on the
source object. A KeyEvent listener must implement KeyListener interface, which declares three
abstract methods:
public void keyTyped(KeyEvent e)
// Called-back when a key has been typed (pressed and released).
public void keyPressed(KeyEvent e)
public void keyReleased(KeyEvent e)
// Called-back when a key has been pressed or released.
1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits from the top-level container java.awt.Frame
5public class KeyEventDemo extends Frame {
6
7 private TextField tfInput; // Single-line TextField to receive tfInput key
8 private TextArea taDisplay; // Multi-line TextArea to taDisplay result
9
10 // Constructor to setup the GUI components and event handlers
11 public KeyEventDemo() {
12 setLayout(new FlowLayout()); // "super" frame sets to FlowLayout
13
14 add(new Label("Enter Text: "));
15 tfInput = new TextField(10);
16 add(tfInput);
17 taDisplay = new TextArea(5, 40); // 5 rows, 40 columns
18 add(taDisplay);
19
20 tfInput.addKeyListener(new MyKeyListener());
21 // tfInput TextField (source) fires KeyEvent.
22 // tfInput adds an anonymous instance of MyKeyListener
23 // as a KeyEvent listener.
24
25 setTitle("KeyEvent Demo"); // "super" Frame sets title
26 setSize(400, 200); // "super" Frame sets initial size
27 setVisible(true); // "super" Frame shows
28 }
29
30 // The entry main() method
31 public static void main(String[] args) {
32 new KeyEventDemo(); // Let the constructor do the job
33 }
34
35 // Define an inner class to handle KeyEvent
36 private class MyKeyListener implements KeyListener {
37 // Called back when a key has been typed (pressed and released)
38 @Override
39 public void keyTyped(KeyEvent evt) {
40 taDisplay.append("You have typed " + evt.getKeyChar() + "\n");
41 }
42
43 // Not Used, but need to provide an empty body for compilation
44 @Override public void keyPressed(KeyEvent evt) { }
45 @Override public void keyReleased(KeyEvent evt) { }
46 }
47}
In this example:
1. We identify the tfInput (of 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. In Line 35-46, we define an inner class called MyKeyListener as the KeyEvent listener.
4. We register an anonymous instance of MyKeyListener as the KeyEvent listener to the
source TextField via method input.addKeyListener().
5. The KeyEvent listener needs to implement the KeyListener interface, which declares 3
abstract methods: keyTyped(), keyPressed(), keyReleased().
6. We override the keyTyped() to display key typed on the display TextArea. We ignore
the keyPressed() and keyReleased().
4. Nested (Inner) Classes
4.1 Without Inner classes
In our AWTCounter example, suppose we would like to write an external ordinary class
(say MyExternalBtnListener) as our ActionEvent listener. This class shall
implement ActionListener interface and override the actionPerformed() method. An example is as
follows:
import java.awt.*; // Using AWT container and component classes
import java.awt.event.*; // Using AWT event classes and listener interfaces
• btnCount.addActionListener(new BtnCountListener());
• The inner class can access the private variable tfCount and count of the outer class.
• The inner class is compiled into AWTCount$BtnCountListener.class , in the format
of OuterClassName$InnerClassName.class.
(Advanced) Using an Ordinary (Outer) Class as Listener
Try moving the BtnCountListener class outside, and define it as an ordinary class. You would need to
pass a reference of the AWTConnter into the constructor of BtnCountListener, and use this reference
to access variables tfCount and count, through public getters or granting them to public access.
// An ordinary outer class used as ActionListener for the Button
public class BtnCountListener implements ActionListener {
// private variable
AWTCounter frame;
// The event handler can access the private variables thru "frame"
@Override
public void actionPerformed(ActionEvent evt) {
frame.count++;
frame.tfCount.setText(frame.count + "");
}
}
});
// Or
N n = new N()
btnCount.addActionListener(n);
• From JDK 8, you can write the event handler using "Lambda Expression" in a one-liner as
follows:
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 AWTCounter3ButtonsAnonymousIC extends Frame {
6 private TextField tfCount;
7 private Button btnCountUp, btnCountDown, btnReset;
8 private int count = 0;
9
10 // Constructor to setup the GUI components and event handlers
11 public AWTCounter3ButtonsAnonymousIC() {
12 setLayout(new FlowLayout());
13 add(new Label("Counter")); // an anonymous instance of Label
14 tfCount = new TextField("0", 10);
15 tfCount.setEditable(false); // read-only
16 add(tfCount); // "super" Frame adds tfCount
17
18 btnCountUp = new Button("Count Up");
19 add(btnCountUp);
20 // Construct an anonymous instance of an anonymous inner class.
21 // The source Button adds the anonymous instance as ActionEvent listener
22 btnCountUp.addActionListener(new ActionListener() {
23 @Override
24 public void actionPerformed(ActionEvent evt) {
25 ++count;
26 tfCount.setText(count + "");
27 }
28 });
29
30 btnCountDown = new Button("Count Down");
31 add(btnCountDown);
32 btnCountDown.addActionListener(new ActionListener() {
33 @Override
34 public void actionPerformed(ActionEvent evt) {
35 count--;
36 tfCount.setText(count + "");
37 }
38 });
39
40 btnReset = new Button("Reset");
41 add(btnReset);
42 btnReset.addActionListener(new ActionListener() {
43 @Override
44 public void actionPerformed(ActionEvent evt) {
45 count = 0;
46 tfCount.setText("0");
47 }
48 });
49
50 setTitle("AWT Counter");
51 setSize(400, 100);
52 setVisible(true);
53 }
54
55 // The entry main method
56 public static void main(String[] args) {
57 new AWTCounter3ButtonsAnonymousIC(); // Let the constructor do the job
58 }
59}
Dissecting the Program
1. Each of the Buttons uses one anonymous instance of an anonymous inner class as
its ActionEvent listener.
4.6 Example 10: Using the Same Listener Instance for All the
Buttons
If you use the same instance as the listener for all the 3 buttons, you need to determine which button
has fired the event. It is because all the 3 buttons trigger the same event-handler method.
Using ActionEvent's getActionCommand()
In the following example, we use the same instance of a "named" inner class as the listener for all the
3 buttons. The listener needs to determine which button has fired the event. This can be accomplished
via the ActionEvent's getActionCommonad() method, which returns the button's label.
1import java.awt.*;
2import java.awt.event.*;
3
4// An AWT GUI program inherits the top-level container java.awt.Frame
5public class AWTCounter3Buttons1Listener extends Frame {
6 private TextField tfCount;
7 private Button btnCountUp, btnCountDown, btnReset;
8 private int count = 0;
9
10 // Constructor to setup the GUI components and event handlers
11 public AWTCounter3Buttons1Listener () {
12 setLayout(new FlowLayout());
13 add(new Label("Counter"));
14 tfCount = new TextField("0", 10);
15 tfCount.setEditable(false);
16 add(tfCount);
17
18 // Construct Buttons
19 btnCountUp = new Button("Count Up");
20 add(btnCountUp);
21 btnCountDown = new Button("Count Down");
22 add(btnCountDown);
23 btnReset = new Button("Reset");
24 add(btnReset);
25
26 // Allocate an instance of the "named" inner class BtnListener.
27 AllButtonsListener listener = new AllButtonsListener();
28 // Use the same listener instance for all the 3 Buttons.
29 btnCountUp.addActionListener(listener);
30 btnCountDown.addActionListener(listener);
31 btnReset.addActionListener(listener);
32
33 setTitle("AWT Counter");
34 setSize(400, 100);
35 setVisible(true);
36 }
37
38 // The entry main method
39 public static void main(String[] args) {
40 new AWTCounter3Buttons1Listener(); // Let the constructor do the job
41 }
42
43 /**
44 * AllButtonsListener is an named inner class used as ActionEvent listener for all the B
45 */
46 private class AllButtonsListener implements ActionListener {
47 @Override
48 public void actionPerformed(ActionEvent evt) {
49 // Need to determine which button fired the event.
50 // the getActionCommand() returns the Button's label
51 String btnLabel = evt.getActionCommand();
52 if (btnLabel.equals("Count Up")) {
53 ++count;
54 } else if (btnLabel.equals("Count Down")) {
55 --count;
56 } else {
57 count = 0;
58 }
59 tfCount.setText(count + "");
60 }
61 }
62}
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 components and event handlers
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 // Construct 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 AllButtonsListener listener = new AllButtonsListener();
27 // Use the same listener instance to all the 3 Buttons.
28 btnCountUp.addActionListener(listener);
29 btnCountDown.addActionListener(listener);
30 btnReset.addActionListener(listener);
31
32 setTitle("AWT Counter");
33 setSize(400, 100);
34 setVisible(true);
35 }
36
37 // The entry main method
38 public static void main(String[] args) {
39 new AWTCounter3ButtonsGetSource(); // Let the constructor do the job
40 }
41
42 /**
43 * AllButtonsListener is a named inner class used as ActionEvent listener for all the Bu
44 */
45 private class AllButtonsListener implements ActionListener {
46 @Override
47 public void actionPerformed(ActionEvent evt) {
48 // Need to determine which button has fired the event.
49 Button source = (Button)evt.getSource();
50 // Get a reference of the source that has fired the event.
51 // getSource() returns a java.lang.Object. Downcast back to Button.
52 if (source == btnCountUp) {
53 ++count;
54 } else if (source == btnCountDown) {
55 --count;
56 } else {
57 count = 0;
58 }
59 tfCount.setText(count + "");
60 }
61 }
62}
For example,
There is only ONE class in this code. But this code is much harder to understand and seldom used
nowadays. Using inner class is a better solution.
For example,
7.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 alignment);
public FlowLayout(int alignment, int hgap, int vgap);
// alignment: 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, alignment = FlowLayout.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 and event handlers
9 public AWTFlowLayoutDemo () {
10 setLayout(new FlowLayout());
11 // "super" Frame sets layout to FlowLayout, which arranges the components
12 // from left-to-right, and flow from top-to-bottom.
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"); // "super" Frame sets title
28 setSize(280, 150); // "super" Frame sets initial size
29 setVisible(true); // "super" 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}
7.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 and event handlers
9 public AWTGridLayoutDemo () {
10 setLayout(new GridLayout(3, 2, 3, 3));
11 // "super" Frame sets layout to 3x2 GridLayout, horizontal and vertical gaps of 3
12pixels
13
14 // The components are added from left-to-right, top-to-bottom
15 btn1 = new Button("Button 1");
16 add(btn1);
17 btn2 = new Button("This is Button 2");
18 add(btn2);
19 btn3 = new Button("3");
20 add(btn3);
21 btn4 = new Button("Another Button 4");
22 add(btn4);
23 btn5 = new Button("Button 5");
24 add(btn5);
25 btn6 = new Button("One More Button 6");
26 add(btn6);
27
28 setTitle("GridLayout Demo"); // "super" Frame sets title
29 setSize(280, 150); // "super" Frame sets initial size
30 setVisible(true); // "super" Frame shows
31 }
32
33 // The entry main() method
34 public static void main(String[] args) {
35 new AWTGridLayoutDemo(); // Let the constructor do the job
36 }
}
7.3 BorderLayout
In java.awt.BorderLayout, the container is divided into 5 zones: EAST, WEST, SOUTH, NORTH,
and CENTER. Components are added using method aContainer.add(aComponent, zone),
where zone is
either BorderLayout.NORTH (or PAGE_START), BorderLayout.SOUTH (or PAGE_END), BorderLayout.WE
ST (or LINE_START), BorderLayout.EAST (or LINE_END), or BorderLayout.CENTER.
You need not place components to all the 5 zones. The NORTH and SOUTH components may be
stretched horizontally; the EAST and WEST components may be stretched vertically;
the CENTER component may stretch both horizontally and vertically to fill any space left over.
Constructors
public BorderLayout();
public BorderLayout(int hgap, int vgap);
// By default hgap = 0, vgap = 0
Example
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 and event handlers
9 public AWTBorderLayoutDemo () {
10 setLayout(new BorderLayout(3, 3));
11 // "super" 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"); // "super" Frame sets title
27 setSize(280, 150); // "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 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 in FlowLayout and panelButtons in GridLayout. panelResult is added
to the NORTH, and panelButtons is added to the CENTER.
1import java.awt.*;
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; // Array of 10 numeric Buttons
7 private Button btnHash, btnStar;
8 private TextField tfDisplay;
9
10 // Constructor to setup GUI components and event handlers
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 = new Button[10]; // Construct an array of 10 numeric Buttons
20 btnNumbers[1] = new Button("1"); // Construct Button "1"
21 panelButtons.add(btnNumbers[1]); // The Panel adds this Button
22 btnNumbers[2] = new Button("2");
23 panelButtons.add(btnNumbers[2]);
24 btnNumbers[3] = new Button("3");
25 panelButtons.add(btnNumbers[3]);
26 btnNumbers[4] = new Button("4");
27 panelButtons.add(btnNumbers[4]);
28 btnNumbers[5] = new Button("5");
29 panelButtons.add(btnNumbers[5]);
30 btnNumbers[6] = new Button("6");
31 panelButtons.add(btnNumbers[6]);
32 btnNumbers[7] = new Button("7");
33 panelButtons.add(btnNumbers[7]);
34 btnNumbers[8] = new Button("8");
35 panelButtons.add(btnNumbers[8]);
36 btnNumbers[9] = new Button("9");
37 panelButtons.add(btnNumbers[9]);
38 // You should use a loop for the above statements!!!
39 btnStar = new Button("*");
40 panelButtons.add(btnStar);
41 btnNumbers[0] = new Button("0");
42 panelButtons.add(btnNumbers[0]);
43 btnHash = new Button("#");
44 panelButtons.add(btnHash);
45
46 setLayout(new BorderLayout()); // "super" Frame sets to BorderLayout
47 add(panelDisplay, BorderLayout.NORTH);
48 add(panelButtons, BorderLayout.CENTER);
49
50 setTitle("BorderLayout Demo"); // "super" Frame sets title
51 setSize(200, 200); // "super" Frame sets initial size
52 setVisible(true); // "super" Frame shows
53 }
54
55 // The entry main() method
56 public static void main(String[] args) {
57 new AWTPanelDemo(); // Let the constructor do the job
58 }
59}
7.5 GridBagLayout
Reference: Read "How to Use GridBagLayout" @
https://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html.
7.6 Example 1
1import java.awt.*;
2import javax.swing.*;
3
4@SuppressWarnings("serial")
5public class GridBagLayoutExample extends JPanel {
6 JButton button1, button2, button3, button4, button5;
7
8 // Constructor
9 public GridBagLayoutExample() {
10 super.setLayout(new GridBagLayout()); // super JPanel
11 GridBagConstraints gbc = new GridBagConstraints();
12
13 // The following constraints are applicable to all components
14// gbc.fill = GridBagConstraints.HORIZONTAL;
15
16 // Define constraints for individual components
17 button1 = new JButton("B1");
18 gbc.gridx = 0; // column 0 (first column)
19 gbc.gridy = 0; // row 0 (first row)
20// gbc.weightx = 0.5; // weight for distributing extra x-spaces
21 super.add(button1, gbc); // add and apply constraints
22
23 button2 = new JButton("B2");
24 gbc.gridx = 1; // column 1
25 gbc.gridy = 0; // row 0
26// gbc.weightx = 1.0;
27 super.add(button2, gbc);
28
29 button3 = new JButton("B3");
30 gbc.gridx = 2; // column 2
31 gbc.gridy = 0; // row 0
32// gbc.weightx = 0.5;
33 super.add(button3, gbc);
34
35 button4 = new JButton("Long-Named Button 4");
36 gbc.gridx = 0; // column 0
37 gbc.gridy = 1; // row 1 (second row)
38 gbc.gridwidth = 3; // span 3 columns
39 gbc.ipady = 40; // internal padding-y
40 super.add(button4, gbc);
41
42 button5 = new JButton("5");
43 gbc.gridx = 1; // second column
44 gbc.gridy = 2; // third row
45 gbc.gridwidth = 2; // span 2 columns
46 gbc.ipady = 0; // reset to default
47 gbc.anchor = GridBagConstraints.PAGE_END; // align at bottom of space
48 gbc.insets = new Insets(10, 0, 0, 0); // top margin
49// gbc.weighty = 1.0; // request any extra vertical space
50 super.add(button5, gbc);
51 }
52
53 public static void main(String[] args) {
54 javax.swing.SwingUtilities.invokeLater(new Runnable() {
55 public void run() {
56 JFrame frame = new JFrame("GridBagLayoutDemo");
57 frame.setContentPane(new GridBagLayoutExample());
58 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
59 frame.setSize(300,300);
60 frame.setVisible(true);
61 }
62 });
63 }
64}
Run the program, the output is in (a), where all components have their natural width and height, placed
in center (anchor=CENTER) with extra x and y spaces at the 4 margins. The ipady increases the internal
y-padding for button-4 (spans 3 columns). Button 5 (spans second and third columns) has top margin
specified by insets, and anchor at the bottom-right corner (anchor=PAGE_END).
Uncomment the gbc.fill = GridBagConstraints.HORIZONTAL (line 14). The output is in (b), where
ALL components fill horizontally with equal column width.
Uncomment all weightx (lines 20, 26, 32). The output is in (c). The extra x spaces are distributed
according to the weightx of (0.5, 1.0, 0.5).
Uncomment the weighty (line 49). The output is in (d). The extra y spaces are given to row 3, as row 1
and 2 have weighty of 0 and non-participating in the distribution of extra y-spaces.
7.7 BoxLayout
BoxLayout arrange components in a single row or column. It respects components' requests on the
minimum sizes.
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.
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
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 SwingDemo extends JFrame {
3. // Constructor
4. public SwingDemo() {
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 = 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's setContentPane().
15. public class SwingDemo extends JFrame {
16. // Constructor
17. public SwingDemo() {
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. 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.,
// Suppose that "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.
Writing Swing Applications
In summary, to write a Swing application, you have:
1. Use the Swing components with prefix "J" in package javax.swing,
e.g., JFrame, JButton, JTextField, JLabel, etc.
2. A top-level container (typically JFrame) is needed. The JComponents should not be
added directly onto the top-level container. They shall be added onto the content-
pane of the top-level container. You can retrieve a reference to the content-pane by
invoking method getContentPane() from the top-level container.
3. Swing applications uses AWT event-handling classes,
e.g., ActionEvent/ActionListener , MouseEvent/MouseListener, etc.
4. Run the constructor in the Event Dispatcher Thread (instead of Main thread) for thread
safety, as shown in the following program template.
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
feel between the AWT GUI components and Swing's.
1import java.awt.*; // Using AWT layouts
2import java.awt.event.*; // Using AWT event classes 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 { // JFrame instead of Frame
7 private JTextField tfCount; // Use Swing's JTextField instead of AWT's TextField
8 private JButton btnCount; // Using Swing's JButton instead of AWT's Button
9 private int count = 0;
10
11 // Constructor to setup the GUI components and event handlers
12 public SwingCounter() {
13 // Retrieve the content-pane of the top-level container JFrame
14 // All operations done on the content-pane
15 Container cp = getContentPane();
16 cp.setLayout(new FlowLayout()); // The content-pane sets its layout
17
18 cp.add(new JLabel("Counter"));
19 tfCount = new JTextField("0");
20 tfCount.setEditable(false);
21 cp.add(tfCount);
22
23 btnCount = new JButton("Count");
24 cp.add(btnCount);
25
26 // Allocate an anonymous instance of an anonymous inner class that
27 // implements ActionListener as ActionEvent listener
28 btnCount.addActionListener(new ActionListener() {
29 @Override
30 public void actionPerformed(ActionEvent evt) {
31 ++count;
32 tfCount.setText(count + "");
33 }
34 });
35
36 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Exit program if close-window butt
37 setTitle("Swing Counter"); // "super" JFrame sets title
38 setSize(300, 100); // "super" JFrame sets initial size
39 setVisible(true); // "super" JFrame shows
40 }
41
42 // The entry main() method
43 public static void main(String[] args) {
44 // Run the GUI construction in the Event-Dispatching thread for thread-safety
45 SwingUtilities.invokeLater(new Runnable() {
46 @Override
47 public void run() {
48 new SwingCounter(); // Let the constructor do the job
49 }
50 });
51 }
52}
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.
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,