Unit VIII - Event Programming.
2.1 AWT Packages
AWT is huge! It consists of 12 packages of 370 classes (Swing is even bigger, with 18 packages of 737 classes as of JDK 8). Fortunately, only 2 packages - java.awt
and java.awt.event
- are commonly-used.
- The
java.awt
package contains the core AWT graphics classes:- GUI Component classes, such as
Button
,TextField
, andLabel
. - GUI Container classes, such as
Frame
andPanel
. - Layout managers, such as
FlowLayout
,BorderLayout
andGridLayout
. - Custom graphics classes, such as
Graphics
,Color
andFont
.
- GUI Component classes, such as
- The
java.awt.event
package supports event handling:- Event classes, such as
ActionEvent
,MouseEvent
,KeyEvent
andWindowEvent
, - Event Listener Interfaces, such as
ActionListener
,MouseListener
,MouseMotionListener
,KeyListener
andWindowListener
, - Event Listener Adapter classes, such as
MouseAdapter
,KeyAdapter
, andWindowAdapter
.
- Event classes, such as
AWT provides a platform-independent and device-independent interface to develop graphic programs that runs on all platforms, including Windows, macOS, and Unixes.
2.2 AWT Containers and Components
There are two groups of GUI elements:
- Component (Widget, Control): Components are elementary GUI entities, such as
Button
,Label
, andTextField
. They are also called widgets, controls in other graphics systems. - Container: Containers, such as
Frame
andPanel
, are used to hold components in a specific layout (such asFlowLayout
orGridLayout
). A container can also hold sub-containers.
In the above figure, there are three containers: a Frame
and two Panel
s. A Frame
is the top-level container of an AWT program. A Frame
has a title bar (containing an icon, a title, and the minimize/maximize/close buttons), an optional menu bar and the content display area. A Panel
is a rectangular area used to group related GUI components in a certain layout. In the above figure, the top-level Frame
contains two Panel
s. There are five components: a Label
(providing description), a TextField
(for users to enter text), and three Button
s (for user to trigger certain programmed actions).
In a GUI program, a component must be kept (or added) in a container. You need to identify a container to hold the components. Every container has a method called add(Component c)
. A container
(say aContainer
) can invoke aContainer.add(aComponent)
to add aComponent
into itself. For example,
Panel pnl = new Panel(); // Panel is a container Button btn = new Button("Press"); // Button is a component pnl.add(btn); // The Panel container adds a Button component
GUI components are also called controls (e.g., Microsoft ActiveX Control), widgets (e.g., Eclipse's Standard Widget Toolkit, Google Web Toolkit), which allow users to interact with (or control) the application.
2.3 AWT Container Classes
Top-Level Containers: Frame, Dialog and Applet
Each GUI program has a top-level container. The commonly-used top-level containers in AWT are Frame
, Dialog
and Applet
:
- A
Frame
provides the "main window" for 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 fromjava.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. ADialog
has a title-bar (containing an icon, a title and a close button) and a content display area, as illustrated. - An AWT
Applet
(in packagejava.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.
AWT GUI Component: java.awt.Label
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:
- The first constructor constructs a
Label
object with the given text string in the given alignment. Note that threestatic
constantsLabel.LEFT
,Label.RIGHT
, andLabel.CENTER
are defined in the class for you to specify the alignment (rather than asking you to memorize arbitrary integer values). - The second constructor constructs a
Label
object with the given text string in default of left-aligned. - The third constructor constructs a
Label
object with an initially empty string. You could set the label text via thesetText()
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:
- Declare the component with an identifier (name);
- Construct the component by invoking an appropriate constructor via the
new
operator; - Identify the container (such as
Frame
orPanel
) designed to hold this component. The container can then add this component onto itself viaaContainer.add(aComponent)
method. Every container has aadd(Component)
method. Take note that it is the container that actively and explicitly adds a component onto itself, NOT the other way.
Example
Label lblInput; // Declare an Label instance called lblInput lblInput = new Label("Enter ID"); // Construct by invoking a constructor via the new operator add(lblInput); // this.add(lblInput) - "this" is typically a subclass of Frame lblInput.setText("Enter password"); // Modify the Label's text string lblInput.getText(); // Retrieve the Label's text string
An Anonymous Label 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. // You CANNOT reference an anonymous instance to carry out further operations. add(new Label("Enter Name: ", Label.RIGHT)); // Same as Label xxx = new Label("Enter Name: ", Label.RIGHT)); // xxx assigned by compiler add(xxx);
AWT GUI Component: java.awt.Button
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
public String getLabel(); // Get the label of this Button instance public void setLabel(String btnLabel); // Set the label of this Button instance public void setEnable(boolean enable); // Enable or disable this Button. Disabled Button cannot be clicked.
The getLabel()
and setLabel()
methods can be used to read the current label and modify the label of a button, respectively.
Note: The latest Swing's JButton
replaces getLabel()/setLabel()
with getText()/setText()
to be consistent with all the components. We will describe Swing later.
Event
Clicking a button fires a so-called ActionEvent
and triggers a certain programmed action. I will explain event-handling later.
Example
Button btnColor = new Button("Red"); // Declare and allocate a Button instance called btnColor add(btnColor); // "this" Container adds the Button ... btnColor.setLabel("Green"); // Change the button's label btnColor.getLabel(); // Read the button's label
AWT GUI Component: java.awt.TextField
A java.awt.TextField
is single-line text box for users to enter texts. (There is a multiple-line text box called TextArea
.) Hitting the "ENTER" key on a TextField
object fires an ActionEvent
.
Constructors
public TextField(String initialText, int columns); // Construct a TextField instance with the given initial text string with the number of columns. public TextField(String initialText); // 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 primitive with an empty String
.
2.5 Example 1: AWTCounter
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.
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 63 64 65 66 | import java.awt.*; // Using AWT container and component classes import java.awt.event.*; // Using AWT event classes and listener interfaces // An AWT program inherits from the top-level container java.awt.Frame public class AWTCounter extends Frame { private Label lblCount; // Declare a Label component private TextField tfCount; // Declare a TextField component private Button btnCount; // Declare a Button component private int count = 0; // Counter's value // Constructor to setup GUI components and event handlers public AWTCounter () { setLayout(new FlowLayout()); // "super" Frame, which is a Container, sets its layout to FlowLayout to arrange // the components from left-to-right, and flow to next row from top-to-bottom. lblCount = new Label("Counter"); // construct the Label component add(lblCount); // "super" Frame container adds Label component tfCount = new TextField(count + "", 10); // construct the TextField component with initial text tfCount.setEditable(false); // set to read-only add(tfCount); // "super" Frame container adds TextField component btnCount = new Button("Count"); // construct the Button component add(btnCount); // "super" Frame container adds Button component BtnCountListener listener = new BtnCountListener(); btnCount.addActionListener(listener); // "btnCount" is the source object that fires an ActionEvent when clicked. // The source object adds an instance of BtnCountListener as an ActionEvent listener, // which provides an ActionEvent handler called actionPerformed(). // Clicking "Count" button calls back actionPerformed(). setTitle("AWT Counter"); // "super" Frame sets its title setSize(300, 100); // "super" Frame sets its initial window size // For inspecting the Container/Components objects // System.out.println(this); // System.out.println(lblCount); // System.out.println(tfCount); // System.out.println(btnCount); setVisible(true); // "super" Frame shows // System.out.println(this); // System.out.println(lblCount); // System.out.println(tfCount); // System.out.println(btnCount); } // The entry main() method public static void main(String[] args) { // Invoke the constructor to setup the GUI, by allocating an instance AWTCounter app = new AWTCounter(); // or simply "new AWTCounter();" for an anonymous instance } // Define an inner class to handle the "Count" button-click private class BtnCountListener implements ActionListener { // ActionEvent handler - Called back upon button-click. @Override public void actionPerformed(ActionEvent evt) { ++count; // Increase the counter value // Display the counter value on the TextField tfCount tfCount.setText(count + ""); // Convert int to String } } } |
To exit this program, you have to close the CMD-shell (or press "control-c" on the CMD console); or push the "red" close button in Eclipse's Application Console. This is because we have yet to write the handler for the Frame
's close button. We shall do that in the later example.
Dissecting the AWTCounter.java
- The
import
statements (Lines 1-2) are needed, as AWT container and component classes, such asFrame
,Button
,TextField
, andLabel,
are kept in thejava.awt
package; while AWT events and event-listener interfaces, such asActionEvent
andActionListener
are kept in thejava.awt.event
package. - A GUI program needs a top-level container, and is often written as a subclass of
Frame
(Line 5). In other words, this classAWTCounter
is aFrame
, and inherits all the attributes and behaviors of aFrame
, such as the title bar and content pane. - Lines 11 to 47 define a constructor, which is used to setup the GUI components and event handlers.
- In Line 13, the
setLayout()
(inherited from the superclassFrame
) is used to set the layout of the container.FlowLayout
is used which arranges the components in left-to-right and flows into next row in a top-to-bottom manner. - A
Label
,TextField
(non-editable), andButton
are constructed. We invoke theadd()
method (inherited from the superclassFrame
) to add these components into container.
- In Line 34-35, we invoke the
setSize()
and thesetTitle()
(inherited from the superclassFrame
) to set the initial size and the title of theFrame
. ThesetVisible(true)
method (Line 42) is then invoked to show the display. - Line 27-28 is used to setup the callback event-handler, which will be discussed in length later. In brief, whenever the button is clicked, the
actionPerformed()
will be called. In theactionPerformed()
(Lines 59-64), the counter value increases by 1 and displayed on theTextField
. - In the entry
main()
method (Lines 50-54), an instance ofAWTCounter
is constructed. The constructor is executed to initialize the GUI components and setup the event-handlers. The GUI program then waits for the user action.
Inspecting Container/Components via toString()
It is interesting to inspect the GUI objects via the toString()
, to gain an insight to these classes. (Alternatively, use a graphic debugger in Eclipse/NetBeans or study the JDK source code.) For example, if we insert the following code before and after the setvisible()
:
System.out.println(this); //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]
2.6 Example 2: AWTAccumulator
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
.
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 java.awt.*; // Using AWT container and component classes import java.awt.event.*; // Using AWT event classes and listener interfaces // An AWT GUI program inherits (customized) from the top-level container // java.awt.Frame public class AWTAccumulator extends Frame { //private Label lblInput; // Declare input Label (to use anonymous) //private Label lblOutput; // Declare output Label (to use anonymous) private TextField tfInput; // Declare input TextField private TextField tfOutput; // Declare output TextField private int sum = 0; // Accumulated sum, init to 0 // Constructor to setup the GUI components and event handlers public AWTAccumulator() { setLayout(new GridLayout(2, 2)); // "super" Frame (Container) sets layout to GridLayout of 2 rows 2 columns. add(new Label("Enter an Integer: ")); // "super" Frame adds an anonymous Label tfInput = new TextField(10); // Construct TextField add(tfInput); // "super" Frame adds TextField tfInput.addActionListener(new TFInputListener()); // "tfInput" is the source object that fires an ActionEvent upon entered. // The source add an anonymous instance of TFInputListener as an ActionEvent // listener, which provides an ActionEvent handler called actionPerformed(). // Hitting "enter" on tfInput invokes actionPerformed(). add(new Label("The Accumulated Sum is: ")); // "super" Frame adds an anonymous Label tfOutput = new TextField(10); // allocate TextField tfOutput.setEditable(false); // read-only add(tfOutput); // "super" Frame adds TextField setTitle("AWT Accumulator"); // "super" Frame sets title setSize(350, 120); // "super" Frame sets initial window size setVisible(true); // "super" Frame shows } // The entry main() method public static void main(String[] args) { // Invoke the constructor to setup the GUI, by allocating an anonymous instance new AWTAccumulator(); } // Define an inner class to handle the input TextField. // An ActionEvent listener must implement ActionListener interface. private class TFInputListener implements ActionListener { // ActionEvent handler - Called back upon hitting "enter" key on TextField @Override public void actionPerformed(ActionEvent evt) { // Get the String entered into the TextField tfInput, convert to int 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 // convert int to String } } } |
Dissecting the AWTAccumulator.java
- An AWT GUI program extends from
java.awt.Frame
(Line 6) - the top-level window container. - In the constructor (Line 14), we constructs 4 components - 2 anonymous
java.awt.Label
s and 2java.awt.TextField
s. TheFrame
adds the components, inGridLayout
. tfInput
(TextField
) is the source object, which fires anActionEvent
upon hitting the Enter key.tfInput
adds an anonymous instance ofTFInputListener
as anActionEvent
handler (Line 23). The listener class needs to implementActionListener
interface and provides implementation to methodactionPerformed()
. Whenever an user hits Enter on thetfInput
(TextField
), theactionPerformed()
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:
- 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 anActionEvent
, clicking a mouse button firesMouseEvent
, typing a key firesKeyEvent
, 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 calledXxxListener
(e.g.,ActionListener
) containing the names of the handler methods (recall that aninterface
contains onlyabstract
methods without implementation). For example, theActionListener
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 theXxxListener
interface. That is, the listeners must provide their own implementations (i.e., programmed responses) to all theabstract
methods declared in theXxxListener
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()
andremoveXxxListener()
to add and remove aXxxEvent
listener from this list. For theActionEvent
, the signature of the methods are:public void addActionListener(ActionListener lis); public void removeActionListener(ActionListener lis);
Take note that the
addXxxListenser()
takes aXxxListener
object as its sole parameter. In other words, it can only add objects of the typeXxxListener
, and its sub-type. SinceXxxListener
is aninterface
, you cannot create instance ofXxxListener
, but need to create instance of a subclass implementing theXxxListener
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. - The source is triggered by a user.
- 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. - 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:
public interface ActionListener {
public void actionPerformed(ActionEvent evt);
// Called back upon button-click (on Button), enter-key pressed (on TextField)
}
Here are the event-handling steps:
- We identify
btnCount
(ofButton
) as the source object. - Clicking
Button
fires anActionEvent
to all itsActionEvent
listener(s). - The listener(s) is required to implement
ActionListener
interface, and override theactionPerformed()
method to provide the response. In Line 56-65, we write an inner class calledBtnCountListener
, which override theactionPerformed()
to increment and display the count. An inner class is a class defined inside an outer class, and it can access the private entities of the outer class. We will elaborate on the inner class in the next section. - The source object registers listener via the
addActionListener()
. In this example, the sourcebtnCount
(Button
) adds an instance ofBtnCountListener
as a listener via:BtnCountListener listener = new BtnCountListener(); btnCount.addActionListener(listener);
Note that
addActionListener()
takes an argument of the typeActionListener
.BtnCountListener
, which implementsActionListener
interface (i.e., a subclass ofActionListener
), is upcasted and passed to theaddActionListener()
method. - Upon button-click, the
btnCount
creates anActionEvent
object, and calls back theactionPerformed(ActionEvent)
method of all its registered listener(s) with theActionEvent
object created:ActionEvent evt = new ActionEvent( ...... ); listener.actionPerformed(evt); // for all its listener(s)
The sequence diagram is as follows:
3.2 Revisit Example 2 AWTAccumulator: ActionEvent and ActionListener Interface
In this example,
- We identify the
tfInput
(ofTextField
) as the source object. - Hitting the "Enter" key on a
TextField
fires anActionEvent
to all itsActionEvent
listener(s). - In Line 46-59, we define an inner class called
TFInputListener
as theActionEvent
listener.TheActionEvent
listener is required to implement theActionListener
interface, and override theactionPerformed()
method to provide the programmed response upon activation. - The source object
tfInput
(ofTextField
) registers an anonymous instance ofTFInputListener
as itsActionEvent
listener via thetfInput.addActionListener(new TFInputListener())
(Line 23).
3.3 Example 3: WindowEvent and WindowListener Interface
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".
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 63 64 65 66 67 68 69 70 | import java.awt.*; // Using AWT containers and components import java.awt.event.*; // Using AWT events classes and listener interfaces // An AWT GUI program inherits the top-level container java.awt.Frame public class WindowEventDemo extends Frame { private TextField tfCount; // Declare a TextField component private Button btnCount; // Declare a Button component private int count = 0; // Counter's value // Constructor to setup the GUI components and event handlers public WindowEventDemo() { setLayout(new FlowLayout()); // "super" Frame sets to FlowLayout add(new Label("Counter")); // "super" Frame adds an anonymous Label tfCount = new TextField("0", 10); // Construct the TextField tfCount.setEditable(false); // read-only add(tfCount); // "super" Frame adds TextField btnCount = new Button("Count"); // Construct the Button add(btnCount); // "super" Frame adds Button btnCount.addActionListener(new BtnCountListener()); // btnCount (source object) fires ActionEvent upon clicking // btnCount adds an anonymous instance of BtnCountListener // as an ActionEvent listener addWindowListener(new MyWindowListener()); // "super" Frame (source object) fires WindowEvent. // "super" Frame adds an anonymous instance of MyWindowListener // as a WindowEvent listener. setTitle("WindowEvent Demo"); // "super" Frame sets title setSize(300, 100); // "super" Frame sets initial size setVisible(true); // "super" Frame shows } // The entry main() method public static void main(String[] args) { new WindowEventDemo(); // Let the construct do the job } // Define an inner class to handle ActionEvent of btnCount private class BtnCountListener implements ActionListener { @Override public void actionPerformed(ActionEvent evt) { ++count; tfCount.setText(count + ""); } } // Define an inner class to handle WindowEvent of this Frame private class MyWindowListener implements WindowListener { // Called back upon clicking close-window button @Override public void windowClosing(WindowEvent evt) { System.exit(0); // Terminate the program } // Not Used, BUT need to provide an empty body to compile. @Override public void windowOpened(WindowEvent evt) { } @Override public void windowClosed(WindowEvent evt) { } // For Debugging @Override public void windowIconified(WindowEvent evt) { System.out.println("Window Iconified"); } @Override public void windowDeiconified(WindowEvent evt) { System.out.println("Window Deiconified"); } @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.
- We identify the
super
Frame
as the source object. - The
Frame
fires theWindowEvent
to all its registeredWindowEvent
listener(s). - In Line 53-69, we define an inner class called
MyWindowListener
as theWindowEvent
listener. It is required to implement theWindowListener
interface, which declares 7 abstract methods:windowOpened()
,windowClosed()
,windowClosing()
,windowActivated()
,windowDeactivated()
,windowIconified()
andwindowDeiconified()
. - We register an anonymous instance of
MyWindowListener
as theWindowEvent
listener to the sourceFrame
via methodaddWindowListener(new MyWindowListener())
. - We override the
windowClosing()
handler to terminate the program usingSystem.exit(0)
. We ignore the other 6 handlers, but required to provide an empty body for compilation.
The sequence diagram is as follow:
3.4 Example 4: MouseEvent and MouseListener Interface
A MouseEvent
is fired when you press, release, or click (press followed by release) a mouse-button (left or right button) at the source object; or position the mouse-pointer at (enter) and away (exit) from the source object.
A MouseEvent
listener must implement the MouseListener
interface, which declares the following five abstract
methods:
public void mouseClicked(MouseEvent evt) // Called-back when the mouse-button has been clicked (pressed followed by released) on the source. public void mousePressed(MouseEvent evt) public void mouseReleased(MouseEvent evt) // Called-back when a mouse-button has been pressed/released on the source. // A mouse-click invokes mousePressed(), mouseReleased() and mouseClicked(). public void mouseEntered(MouseEvent evt) public void mouseExited(MouseEvent evt) // Called-back when the mouse-pointer has entered/exited the source.
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 | import java.awt.*; import java.awt.event.*; public class MouseEventDemo extends Frame { private TextField tfMouseX; // to display mouse-click-x private TextField tfMouseY; // to display mouse-click-y // Constructor - Setup the UI components and event handlers public MouseEventDemo() { setLayout(new FlowLayout()); // "super" frame sets its layout to FlowLayout // Label (anonymous) add(new Label("X-Click: ")); // "super" frame adds Label component // TextField tfMouseX = new TextField(10); // 10 columns tfMouseX.setEditable(false); // read-only add(tfMouseX); // "super" frame adds TextField component // Label (anonymous) add(new Label("Y-Click: ")); // "super" frame adds Label component // TextField tfMouseY = new TextField(10); tfMouseY.setEditable(false); // read-only add(tfMouseY); // "super" frame adds TextField component addMouseListener(new MyMouseListener()); // "super" frame (source) fires the MouseEvent. // "super" frame adds an anonymous instance of MyMouseListener // as a MouseEvent listener. setTitle("MouseEvent Demo"); // "super" Frame sets title setSize(350, 100); // "super" Frame sets initial size setVisible(true); // "super" Frame shows } public static void main(String[] args) { new MouseEventDemo(); // Let the constructor do the job } // Define an inner class to handle MouseEvent private class MyMouseListener implements MouseListener { // Called back upon mouse clicked @Override public void mouseClicked(MouseEvent evt) { tfMouseX.setText(evt.getX() + ""); tfMouseY.setText(evt.getY() + ""); } // Not used - need to provide an empty body to compile. @Override public void mousePressed(MouseEvent evt) { } @Override public void mouseReleased(MouseEvent evt) { } @Override public void mouseEntered(MouseEvent evt) { } @Override public void mouseExited(MouseEvent evt) { } } } |
In this example, we setup a GUI with 4 components (two anonynous Label
s and two non-editable TextField
s) inside a top-level container Frame
, arranged in FlowLayout
.
To demonstrate the MouseEvent
:
- We identity
super
Frame
as the source object. - The
Frame
fires aMouseEvent
to all itsMouseEvent
listener(s) when you click/press/release a mouse-button or enter/exit with the mouse-pointer. - In Line 42-56, we define an inner class called
MyMouseListener
as theMouseEvent
listener. It is required to implement theMouseListener
interface, which declares 5 abstract methods:mouseClicked()
,mousePressed()
,mouseReleased()
,mouseEntered()
, andmouseExit()
. We override themouseClicked()
to display the (x, y) coordinates of the mouse click on the two displayedTextField
s. We ignore all the other handlers (for simplicity - but you need to provide an empty body for compilation). - We register an anonymous instance of
MyMouseListener
as theMouseEvent
listener tosuper
Frame
(source) via the methodaddMouseListener(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.
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | import java.awt.*; import java.awt.event.*; // An AWT GUI program inherits from the top-level container java.awt.Frame public class MouseMotionDemo extends Frame { // To display the (x, y) of the mouse-clicked private TextField tfMouseClickX; private TextField tfMouseClickY; // To display the (x, y) of the current mouse-pointer position private TextField tfMousePositionX; private TextField tfMousePositionY; // Constructor to setup the GUI components and event handlers public MouseMotionDemo() { setLayout(new FlowLayout()); // "super" frame sets to FlowLayout add(new Label("X-Click: ")); tfMouseClickX = new TextField(10); tfMouseClickX.setEditable(false); add(tfMouseClickX); add(new Label("Y-Click: ")); tfMouseClickY = new TextField(10); tfMouseClickY.setEditable(false); add(tfMouseClickY); add(new Label("X-Position: ")); tfMousePositionX = new TextField(10); tfMousePositionX.setEditable(false); add(tfMousePositionX); add(new Label("Y-Position: ")); tfMousePositionY = new TextField(10); tfMousePositionY.setEditable(false); add(tfMousePositionY); MyMouseListener listener = new MyMouseListener(); addMouseListener(listener); addMouseMotionListener(listener); // "super" frame (source) fires MouseEvent. // "super" frame adds an instance of MyMouseListener // as MouseListener and MouseMotionListener. setTitle("MouseMotion Demo"); // "super" Frame sets title setSize(400, 120); // "super" Frame sets initial size setVisible(true); // "super" Frame shows } // The entry main() method public static void main(String[] args) { new MouseMotionDemo(); // Let the constructor do the job } // Define an inner class as both the MouseListener and MouseMotionListener // A Java class can extend one superclass but implement many interfaces private class MyMouseListener implements MouseListener, MouseMotionListener { /* MouseListener handlers */ // Called back when a mouse-button has been clicked @Override public void mouseClicked(MouseEvent evt) { tfMouseClickX.setText(evt.getX() + ""); tfMouseClickY.setText(evt.getY() + ""); } // Not Used, but need to provide an empty body for compilation @Override public void mousePressed(MouseEvent evt) { } @Override public void mouseReleased(MouseEvent evt) { } @Override public void mouseEntered(MouseEvent evt) { } @Override public void mouseExited(MouseEvent evt) { } /* MouseMotionEvent handlers */ // Called back when the mouse-pointer has been moved @Override public void mouseMoved(MouseEvent evt) { tfMousePositionX.setText(evt.getX() + ""); tfMousePositionY.setText(evt.getY() + ""); } // 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
.
- We identify the
super
Frame
as the source, which fires theMouseEvent
to its registeredMouseListener
andMouseMotionListener
.
- In Line 53-80, we define an inner class called
MyMouseListener
as both theMouseListener
andMouseMotionListner
. - We register an instance of
MyMouseListener
as thesuper
Frame
via methodaddMouseListener()
andaddMouseMotionListener()
. - The
MouseMotionListener
needs to implement 2 abstract methods:mouseMoved()
andmouseDragged()
declared in theMouseMotionListener
interface. - We override the
mouseMoved()
to display the (x, y) position of the mouse pointer. We ignore theMouseDragged()
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.
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 | import java.awt.*; import java.awt.event.*; // An AWT GUI program inherits from the top-level container java.awt.Frame public class KeyEventDemo extends Frame { private TextField tfInput; // Single-line TextField to receive tfInput key private TextArea taDisplay; // Multi-line TextArea to taDisplay result // Constructor to setup the GUI components and event handlers 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(new MyKeyListener()); // tfInput TextField (source) fires KeyEvent. // tfInput adds an anonymous instance of MyKeyListener // 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 } // Define an inner class to handle KeyEvent private class MyKeyListener implements KeyListener { // Called back when a key has been typed (pressed and released) @Override public void keyTyped(KeyEvent evt) { taDisplay.append("You have typed " + evt.getKeyChar() + "\n"); } // Not Used, but need to provide an empty body for compilation @Override public void keyPressed(KeyEvent evt) { } @Override public void keyReleased(KeyEvent evt) { } } } |
In this example:
- We identify the
tfInput
(ofTextField
) as the source object. - The source fires a
KeyEvent
when you press/release/type a key to all itsKeyEvent
listener(s). - In Line 35-46, we define an inner class called
MyKeyListener
as theKeyEvent
listener. - We register an anonymous instance of
MyKeyListener
as theKeyEvent
listener to the sourceTextField
via methodinput.addKeyListener()
. - The
KeyEvent
listener needs to implement theKeyListener
interface, which declares 3 abstract methods:keyTyped()
,keyPressed()
,keyReleased()
. - We override the
keyTyped()
to display key typed o
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.
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.*; // An AWT GUI program inherits the top-level container java.awt.Frame public class AWTCounter3Buttons1Listener extends Frame { private TextField tfCount; private Button btnCountUp, btnCountDown, btnReset; private int count = 0; // Constructor to setup the GUI components and event handlers public AWTCounter3Buttons1Listener () { setLayout(new FlowLayout()); add(new Label("Counter")); tfCount = new TextField("0", 10); tfCount.setEditable(false); add(tfCount); // Construct 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 the "named" inner class BtnListener. AllButtonsListener listener = new AllButtonsListener(); // Use the same listener instance for 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 } /** * AllButtonsListener is an named inner class used as ActionEvent listener for all the Buttons. */ private class AllButtonsListener implements ActionListener { @Override public void actionPerformed(ActionEvent evt) { // Need to determine which button fired the event. // the getActionCommand() returns the Button's label String btnLabel = evt.getActionCommand(); if (btnLabel.equals("Count Up")) { ++count; } else if (btnLabel.equals("Count Down")) { --count; } else { count = 0; } tfCount.setText(count + ""); } } } |
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,
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 components and event handlers public AWTCounter3ButtonsGetSource () { setLayout(new FlowLayout()); add(new Label("Counter")); tfCount = new TextField("0", 10); tfCount.setEditable(false); add(tfCount); // Construct 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. AllButtonsListener listener = new AllButtonsListener(); // Use the same listener instance 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 } /** * AllButtonsListener is a named inner class used as ActionEvent listener for all the Buttons. */ private class AllButtonsListener implements ActionListener { @Override public void actionPerformed(ActionEvent evt) { // Need to determine which button has fired the event. Button source = (Button)evt.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 + ""); } } } |
5. Event Listener's Adapter Classes
5.1 Example 11: WindowAdapter for WindowListener
Using WindowListener Interface
Refer to the WindowEventDemo
, a WindowEvent
listener is required to implement the WindowListener
interface, which declares 7 abstract
methods. Although we are only interested in windowClosing()
, we need to provide an empty body to the other 6 abstract
methods in order to compile the program. This is tedious, e.g., we can rewrite the WindowEventDemo
using an inner class implementing ActionListener
as follows:
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 | import java.awt.*; import java.awt.event.*; // An AWT GUI program inherits the top-level container java.awt.Frame public class WindowEventDemoWithInnerClass extends Frame { private TextField tfCount; private Button btnCount; private int count = 0; // Constructor to setup the GUI components and event handlers public WindowEventDemoWithInnerClass () { setLayout(new FlowLayout()); add(new Label("Counter")); tfCount = new TextField("0", 10); tfCount.setEditable(false); add(tfCount); 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 implements WindowListener. // "super" Frame adds this instance as WindowEvent listener. addWindowListener(new WindowListener() { @Override public void windowClosing(WindowEvent evt) { System.exit(0); // terminate the program } // Need to provide an empty body for compilation @Override public void windowOpened(WindowEvent evt) { } @Override public void windowClosed(WindowEvent evt) { } @Override public void windowIconified(WindowEvent evt) { } @Override public void windowDeiconified(WindowEvent evt) { } @Override public void windowActivated(WindowEvent evt) { } @Override public void windowDeactivated(WindowEvent evt) { } }); setTitle("WindowEvent Demo"); setSize(250, 100); setVisible(true); } // The entry main method public static void main(String[] args) { new WindowEventDemoWithInnerClass(); // Let the constructor do the job } } |
Using WindowAdapter Superclass
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 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 | 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 Button btnCount; private int count = 0; // Constructor to setup the GUI components and event handlers public WindowEventDemoAdapter () { setLayout(new FlowLayout()); add(new Label("Counter")); tfCount = new TextField("0", 10); tfCount.setEditable(false); add(tfCount); 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. // "super" Frame adds the instance as WindowEvent listener. addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent evt) { 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 } } |
Clearly, the adapter greatly simplifies the codes.
5.2 Other Event-Listener Adapter Classes
Similarly, adapter classes such as MouseAdapter
, MouseMotionAdapter
, KeyAdapter
, FocusAdapter
are available for MouseListener
, MouseMotionListener
, KeyListener
, and FocusListener
, respectively.
There is no ActionAdapter
for ActionListener
, because there is only one abstract
method (i.e. actionPerformed()
) declared in the ActionListener
interface. This method has to be overridden and there is no need for an adapter.
7. Layout Managers and Panel
A container has a so-called layout manager to arrange its components. The layout managers provide a level of abstraction to map your user interface on all windowing systems, so that the layout can be platform-independent.
AWT provides the following layout managers (in package java.awt
): FlowLayout
, GridLayout
, BorderLayout
, GridBagLayout
, BoxLayout
, CardLayout
, and others. Swing added more layout manager in package javax.swing
, to be described later.
Container's setLayout() method
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:
- Construct an instance of the chosen layout object, via
new
and constructor, e.g.,new FlowLayout()
) - Invoke the
setLayout()
method of theContainer
, with the layout object created as the argument; - Place the GUI components into the
Container
using theadd()
method in the correct order; or into the correct zones.
For example,
// Allocate a Panel (container) Panel pnl = new Panel(); // Allocate a new Layout object. The Panel container sets to this layout. pnl.setLayout(new FlowLayout()); // The Panel container adds components in the proper order. pnl.add(new JLabel("One")); pnl.add(new JLabel("Two")); pnl.add(new JLabel("Three")); ......
Container's getLayout() method
You can get the current layout via Container
's getLayout()
method.
Panel pnl = new Panel();
System.out.println(pnl.getLayout());
// java.awt.FlowLayout[hgap=5,vgap=5,align=center]
Panel's Initial Layout
Panel
(and Swing's JPanel
) provides a constructor to set its initial layout manager. It is because a primary function of Panel
is to layout a group of component in a particular layout.
public void Panel(LayoutManager layout) // Construct a Panel in the given layout // By default, Panel (and JPanel) has FlowLayout // For example, create a Panel in BorderLayout Panel pnl = new Panel(new BorderLayout());
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
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 | 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 and event handlers public AWTFlowLayoutDemo () { setLayout(new FlowLayout()); // "super" Frame sets layout to FlowLayout, which arranges the components // from left-to-right, and flow from 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); setTitle("FlowLayout Demo"); // "super" Frame sets title setSize(280, 150); // "super" Frame sets initial size setVisible(true); // "super" Frame shows } // The entry main() method public static void main(String[] args) { new AWTFlowLayoutDemo(); // Let the constructor do the job } } |
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
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 26 27 28 29 30 31 32 33 34 35 36 | 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 and event handlers public AWTGridLayoutDemo () { setLayout(new GridLayout(3, 2, 3, 3)); // "super" Frame sets layout to 3x2 GridLayout, horizontal and vertical 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); setTitle("GridLayout Demo"); // "super" Frame sets title setSize(280, 150); // "super" Frame sets initial size setVisible(true); // "super" Frame shows } // The entry main() method public static void main(String[] args) { new AWTGridLayoutDemo(); // Let the constructor do the job } } |
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.WEST
(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
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 | 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 and event handlers public AWTBorderLayoutDemo () { setLayout(new BorderLayout(3, 3)); // "super" 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"); // "super" Frame sets title setSize(280, 150); // "super" Frame sets initial size setVisible(true); // "super" Frame shows } // The entry main() method public static void main(String[] args) { new AWTBorderLayoutDemo(); // Let the constructor do the job } } |
7.4 Using Panels as Sub-Container to Organize Components
An AWT Panel
is a rectangular pane, which can be used as sub-container to organized a group of related components in a specific layout (e.g., FlowLayout
, BorderLayout
). Panel
s 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
.
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 | 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; // Array of 10 numeric Buttons private Button btnHash, btnStar; private TextField tfDisplay; // Constructor to setup GUI components and event handlers 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 = new Button[10]; // Construct an array of 10 numeric Buttons btnNumbers[1] = new Button("1"); // Construct Button "1" panelButtons.add(btnNumbers[1]); // The Panel adds this Button 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]); // You should 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()); // "super" Frame sets to BorderLayout add(panelDisplay, BorderLayout.NORTH); add(panelButtons, BorderLayout.CENTER); setTitle("BorderLayout Demo"); // "super" Frame sets title setSize(200, 200); // "super" Frame sets initial size setVisible(true); // "super" Frame shows } // The entry main() method public static void main(String[] args) { new AWTPanelDemo(); // Let the constructor do the job } } |
Comments
Post a Comment