Download Introduction to Building GUIs with AWT and Swing

Document related concepts
no text concepts found
Transcript
SYSC 1101 Object-Oriented Software Development
Building Graphical User Interfaces with Java:
Introduction to AWT and Swing
•
•
Copyright © 1998-2005 D.L. Bailey, Systems and Computer Engineering, Carleton University
revised March 30, 2005
1
What's In This Part of the Course?
• We are going to introduce you to building applications
with graphical user interfaces (GUIs), using Java's
Abstract Windowing Toolkit (AWT) & Swing toolkit
• These toolkits also serve as an example of a fairly
large class hierarchy that exploits the fundamental
O-O concepts supported by Java (classes, objects,
inheritance, polymorphism, abstract classes,
interfaces)
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
2
1
What's In This Part of the Course?
• Looking at all of the classes in the AWT & Swing
would take an entire course (or longer)
– we introduce enough classes to illustrate the key
concepts, but you'll have more opportunities to
use these toolkits in later courses
• We won't spend much time in lectures looking at the
details of the API for these classes
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
3
What's In This Part of the Course?
• Suggestion: experiment!
– run the example programs, use the Java Platform
API specification to understand each method
invocation in the example programs, then modify
these programs & observe the changes in their
appearance & behaviour
• For more info, see the "Creating a GUI with
JFC/Swing" trail in "The Java Tutorial":
http://java.sun.com/docs/books/tutorial/uiswing/index.html
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
4
2
java.awt - The Abstract Windowing Toolkit
• Introduced with Java 1.0
• Classes are divided into 3 main categories:
– graphics (colours, fonts, shapes, etc.)
– components (GUI components: windows, buttons,
menus, etc.)
– layout managers (control the positioning of
components on the screen)
• Each component corresponds to a “peer” component
provided by the native GUI toolkit on the target
platform (Windows, Sun Solaris, etc.)
• Here is a subset of the AWT class hierarchy:
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
Classes for building
menus are subclasses
of Object
Most AWT components;
e.g., Button, Canvas,
CheckBox, Choice (a
pop-up menu of choices),
Label, List (a list of
Strings), Scrollbar,
TextArea and TextField,
are subclasses of
Component
Component
Container
Window
Frame
Object
Dialog
FileDialog
5
Panel
Applet
ScrollPane
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
6
3
java.awt - The Abstract Windowing Toolkit
• Component
– an abstract class
– superclass of all GUI components except menu
components and class CheckboxGroup
• Container
– the superclass for all components that contain
other components
– defines add(), for adding components to a
container
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
7
java.awt - The Abstract Windowing Toolkit
• Window
– a top-level window with no border or menu bar
– rarely instantiated (its subclasses are more useful)
• Frame
– a window with a border and a title bar
– can have a menu bar
– top-level window for Java AWT-based applications
• typically, main() creates an instance of
Frame as its top-level application window, then
adds GUI components to the frame
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
8
4
java.awt - The Abstract Windowing Toolkit
• Dialog
– a dialog window, a.k.a. dialog box
• FileDialog
– a dialog window that allows a user to select a file
• ScrollPane
– a container that contains a single child
component, and provides scrollbars to scroll over
that component
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
9
java.awt - The Abstract Windowing Toolkit
• Panel
– a container that must be contained within another
container
– does not have its own window
• Applet
– a subclass of Panel
– actually part of the java.applet package, not
the AWT
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
10
5
AWT Limitations
• The “look and feel” of AWT-based programs differs
slightly across platforms, because of differences in
the underlying native GUI elements
• AWT components are limited to those that have peer
components on all platforms ("lowest common
denominator")
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
11
javax.swing - The Swing Toolkit
• In response to the AWT, Netscape developed the
Internet Foundation Classes, which evolved into the
Swing toolkit (part of Sun’s Java Foundation Classes
(JFC))
• Swing components do not require native peer
components
• Each Swing UI component is painted onto a blank
window
• Only peer functionality required is the ability to
display windows and paint on them
• Here is a (small) subset of the Swing class hierarchy,
showing its relationship to the AWT classes:
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
12
6
Object
Most (but not all) Swing
classes begin with the
letter "J"
JComponent
JPanel
Component
JScrollPane
Container
Window
JFileChooser
...
Box
Frame
Dialog
JFrame
FileDialog
JWindow
JDialog
Panel
Applet
ScrollPane
JApplet
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
13
javax.swing - The Swing Toolkit
• JWindow, JFrame, JDialog, JPanel, JApplet,
JScrollPane, and JFileChooser are the Swing
counterparts of the AWT's Window, Frame, Dialog,
Panel, Applet, ScrollPane and FileDialog
classes
• JComponent is the base class of most of the Swing
components, including those dealing with menus
– Swing has many more components than AWT
• Use the Swing classes instead of the corresponding
AWT classes
• Box is a lightweight container (more later...)
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
14
7
Some Swing Components
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
15
Some Swing Components
• Not shown in the screen shot are:
– components for building drop-down, pop-up, and
pull-right menus: JMenuBar, JMenu,
JPopupMenu, JMenuItem,
JCheckBoxMenuItem,
JRadioButtonMenuItem, JSeparator
– components for building 2-D tables: JTable,
JTableHeader
– panes: JSplitPane, JTabbedPane,
JLayeredPane, JEditorPane, JTextPane,
JDesktopPane
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
16
8
Some Swing Components
– JToolBar: a toolbar for displaying commonly
used controls
– JToolTip: displays a "tip" for a component
– JOptionPane: class for creating and displaying
standard dialog boxes
– Misc. classes: JColorChooser,
JInternalFrame, JPasswordField,
JScrollbar, JTextArea, JTree, JViewport
– Browse the API documentation for the classes in
the javax.swing.* packages
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
17
First Swing Example: An Up/Down Counter
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
18
9
First Swing Example: An Up/Down Counter
• Clicking the Up button causes the count to be
incremented by 1
• Clicking the Down button causes the count to be
decremented by 1
– this button is enabled only when the count is > 0
• Clicking the Reset button clears the count to 0
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
19
MVC Architecture
• One widely-accepted way of structuring a GUI-based
application is to use the model-view-controller (MVC)
architecture
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
20
10
MVC Architecture
Controller
The controller runs in response to user
input (mouse clicks, key presses), and
sends requests to the model.
Model
View
The view displays information
from the model in the user
interface.
The model contains the
"domain objects" (the core
application logic). When the
model's state changes, it
requests the view to update
itself.
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
21
First Version of Class CounterModel
public class CounterModel
{
private int count;
public CounterModel() {
count = 0;
}
public void increment() { count++; }
public void decrement() {
if (count > 0)
count--;
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
22
11
First Version of Class CounterModel
public void reset() { count = 0; }
public int value { return count; }
public String toString() {
return Integer.toString(count);
}
public boolean equals(Object o) {...}
}
• Notice that this class does not inform the view when
the model's state changes (will fix this later)
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
23
First Version of Class CounterView
import javax.swing.*;
public class CounterView
extends JFrame
{
private CounterModel model;
Note: the
package name is
javax, not java
public CounterView(CounterModel model) {
super("Counter");
this.model = model;
}
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
24
12
First Version of Class CounterView
• A JFrame is used as the top-level window for a
Swing-based application
– CounterView is declared to be a subclass of
JFrame
• JFrame has two constructors:
– JFrame() creates an untitled JFrame object
– JFrame(String title) creates a JFrame
object with the specified title
• Here, we use super(String) to invoke
JFrame(String)
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
25
First Version of Class Counter
• This class creates an instance of the model and the
view
public class Counter
{
public static void main(String[] args) {
CounterModel model = new CounterModel();
CounterView view = new CounterView(model);
view.setResizable(false);
view.setSize(400, 300);
view.setVisible(true);
}
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
26
13
First Version of Class Counter
• By default, a frame is sized at at 0x0 pixels, so
setSize() is sent to the frame to change it size to
400 pixels wide x 300 pixels high
– setSize() is inherited from Component
• If the setSize() message is not sent, only the title
bar is displayed
• The setVisible() message is sent to the frame to
make it visible
– setVisible() is inherited from Component
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
27
Running the Counter App
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
28
14
Closing a Frame
• Clicking on the Close button or selecting Close from
the left-most drop-down menu hides the frame but
does not close the application
• When a user attempts to close a JFrame, the default
behaviour is to hide the frame
• We can invoke setDefaultCloseOperation() to
change the default behaviour
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
29
Closing a Frame
• Symbolic constants for the method's arguments are
defined in interface WindowConstants and
inherited by JFrame
– DISPOSE_ON_CLOSE
– DO_NOTHING_ON_CLOSE
– EXIT_ON_CLOSE
– HIDE_ON_CLOSE
• See the API documentation for JFrame for more
information on the meaning of these constants
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
30
15
Closing a Frame
• When the user closes the frame, we want the
application to terminate by invoking
System.exit(), so we set the default close
operation to EXIT_ON_CLOSE
– add this statement to Counter():
view.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE);
• It works! Now we can populate the frame with
components
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
31
A JFrame Consists of 4 Panes
Title
JFrame
JRootPane
JLayeredPane
optional menu bar
content pane
glass pane
Adapted from Core Java 1.2,
Volume 1 - Fundamentals,
Horstmann & Cornell
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
32
16
Containers and Components
• Components are placed in the frame by adding them
to the frame's content pane
• JFrame’s getContentPane() method returns the
frame's content pane (a Container)
• Container defines several add() methods for
adding Component objects to the container
• Example:
// assume that f refers to a JFrame and
// comp refers to a Component
Container contentPane = f.getContentPane();
contentPane.add(comp);
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
33
Component Layout
• Components are (normally) not placed in a content
pane by specifying their (x,y) coordinates
– what looks good in one environment may not look
as good in another environment
• Instead, each Container object has a layout
manager object that controls how components are
positioned in the container
• Layout managers are defined by two interfaces in the
java.awt package: LayoutManager and
LayoutManager2
• Here are the layout managers that are most
frequently used by application developers:
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
34
17
Border Layout
• The default layout manager for a JFrame’s content
pane object is a BorderLayout object
• A border layout divides the container into 5 regions:
“North”, “South”, “East”, “West”, and “Center”
• One component can be placed in each region
• See the API for java.awt.BorderLayout
• BorderLayoutDemo.java produces the frame
shown on the next slide
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
35
Border Layout
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
36
18
Flow Layout
• A flow layout arranges components in a left to right
flow, like words placed in lines of text in a paragraph
• If the container changes shape, the components flow
to new positions
• See the API for java.awt.FlowLayout
• FlowLayoutDemo.java produces the frame shown
on the next slide
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
37
Flow Layout
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
38
19
Grid Layout
• This layout manager lays out the panel’s components
in a rectangular grid
• The container is divided into equal-sized rectangles,
and one component is placed in each rectangle
• See the API for java.awt.GridLayout
• GridLayoutDemo.java produces the frame shown
on the next slide
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
39
Grid Layout
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
40
20
Box Layout
• A box layout arranges components horizontally (leftto-right placement) or vertically (top-to-bottom
placement) in the same order that they are added to
the container
• The major axis (X-axis or Y-axis) is specified when
the BoxLayout object is created
• See the API for javax.swing.BoxLayout
• BoxLayoutDemo.java produces the frame shown
on the next slide
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
41
Box Layout: Vertical Orientation
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
42
21
Box Layout: Horizontal Orientation
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
43
Components and Containers
• It might seem that are layout choices are limited
• Have another look at the AWT/Swing class hierarchy
(see next slide)
• A Container (and any subclass of Container) is a
subclass of Component; i.e., a Container is-a kind
of Component
• So, we can put containers in containers
• Commonly used Swing containers are JPanel and
Box
– in theory, any Swing component can be a
container, because they are all subclasses of
JComponent
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
44
22
Object
Most (but not all) Swing
classes begin with the
letter "J"
JComponent
JPanel
Component
JScrollPane
Container
Window
JFileChooser
...
Box
Frame
Dialog
JFrame
FileDialog
JWindow
JDialog
Panel
Applet
ScrollPane
JApplet
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
45
Nesting Containers
• This means we can put components in a JPanel (or
a Box) and put the JPanel (Box) in the JFrame’s
content pane
– we can even put JPanel and Box objects inside
JPanel and Box objects
• Each Container has its own layout manager, which
can be changed by sending the container the
setLayout() message, passing a new layout
manager object as the message argument
– the default layout manager for a JPanel is a
FlowLayout object
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
46
23
Component Nesting
JComponent
JPanel
JComponent
content pane
of JFrame
(a Container)
JComponent
JPanel
JComponent
JComponent
JPanel
JComponent
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
47
Counter App GUI Components
JTextField
content pane
of JFrame
(a Container)
JButton
JButton
JPanel
JButton
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
48
24
Second Version of Class CounterView
import java.awt.*;
import javax.swing.*;
public class CounterView extends JFrame
{
private JTextField counterDisplay;
private JButton upButton;
private JButton downButton;
private JButton resetButton;
public CounterView(CounterModel model) {
super("Counter");
Container contentPane =
this.getContentPane();
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
49
Second Version of Class CounterView
counterDisplay = new JTextField();
counterDisplay.setEditable(false);
counterDisplay.setFont(
new Font(null, Font.BOLD, 18));
counterDisplay.
setHorizontalAlignment(JTextField.RIGHT);
contentPane.add(counterDisplay,
BorderLayout.NORTH);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(
new GridLayout(1, 3));
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
50
25
Second Version of Class CounterView
//
//
//
//
//
//
//
//
//
or
buttonPanel.setLayout(
new BoxLayout(buttonPanel,
BoxLayout.X_AXIS));
or, we could use a FlowLayout manager.
Since this is the JPanel's default
layout manager, there would be no
need to create a new FlowLayout object.
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
51
Second Version of Class CounterView
upButton = new JButton("Up");
buttonPanel.add(upButton);
downButton = new JButton("Down");
buttonPanel.add(downButton);
resetButton = new JButton("Reset");
buttonPanel.add(resetButton);
contentPane.add(buttonPanel,
BorderLayout.CENTER);
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
52
26
Running the Counter App
• The view looks o.k. (except that the value of the
counter isn't displayed)
• Clicking the buttons has no effect, because they
aren't "hooked up" to the model
• To do that, we have to design the controller
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
53
How Does a GUI-based Program Obtain Input?
• We’ve seen how to use JOptionPane’s
showInputDialog() method to get input from the
user
– it waits for the user to type a string in the box’s text
field and press the OK button
• In a GUI-based program, there can be several
sources of input; e.g., clicking a button, moving a
slider, typing characters in a text field, etc.
• Invoking methods to wait for user input at specific
component won’t work, because we can’t predict
where the next input will come from
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
54
27
Event-Driven Programs
• GUI-based Java programs use a technique known as
event-driven programming
• In an event-driven program, instead of having objects
send messages to components to wait for input, the
components send messages to event listener objects
when input actions occur
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
55
The Java 1.0 Event Model
• Adequate for simple applets, but not sufficient to build
large-scale event-driven applications
• Java developers are encouraged to use the newer
Java 1.1 event model
– you have stumbled into the Java 1.0 event model
if you find yourself using:
• class java.awt.Event
• any of the following methods from class
Component:
handleEvent(), action(), gotFocus(),
keyDown(), keyUp(), lostFocus(),
mouseDown(), mouseDrag(), mouseEnter(),
mouseExit(), mouseMove(), mouseUp()
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
56
28
The Java 1.1 Event Model
• Objects that generate events in response to user
actions are called event sources
– click on a button
– move mouse in a frame
– type a key in a text field
– etc.
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
57
The Java 1.1 Event Model
• Different types of events are represented by different
Java classes
• java.util.EventObject
– superclass of all Java 1.1 events (AWT,
JavaBeans)
• java.awt.AWTEvent
– superclass of all Java 1.1 AWT events
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
58
29
The Java 1.1 Event Model
• Each AWT event is represented by its own subclass;
e.g.,
– java.awt.event.ActionEvent
– java.awt.event.MouseEvent
• Swing adds additional event classes, but uses the
Java 1.1 event model
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
59
The Java 1.1 Event Model
• Objects that receive events are called event listeners
– package java.awt.event provides a number of
listener interfaces (usually one for each type of
event)
– to process events, we develop classes that
implement the appropriate listener interfaces
– event listener objects are created from these
classes
– aside - for many events, there are abstract adapter
classes that implement the listener interfaces
• listener classes extend these adapter classes
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
60
30
The Java 1.1 Event Model
• Each event source maintains a list of event listeners
that are to be notified when events occur
– source object provides methods to add and
remove listener objects from the list
• The Java Virtual Machine watches for the user’s
actions on GUI components; e.g.,
– mouse movement/dragging, clicks on components
– key presses
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
61
The Java 1.1 Event Model
• When the JVM detects that user has interacted with a
GUI component (e.g. clicking a button), the event
source creates an event object that corresponds to
the action, and notifies all of its listener objects that
the event has occurred
– source object invokes a method provided by the
listener objects
– the event object is passed to this method
• The listeners then handle the event (typically by
sending requests to other objects)
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
62
31
Example
• A JButton is a source of ActionEvent events,
which are generated when the button is clicked
• The listener object that receives these events is an
instance of a class that implements the
ActionListener interface
• This interface declares a single method:
public void actionPerformed(ActionEvent e)
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
63
Example
Here's a first attempt at implementing a listener for the
counter app's Up button:
class UpButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e) {
System.out.println("Up button clicked");
}
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
64
32
Example
• The listener object must be created and registered
with the JButton before it can receive events from
the button
• To do this we invoke the button's
addActionListener() method
ActionListener upButtonListener =
new UpButtonListener();
upButton.addActionListener(upButtonListener);
or simply,
upButton.addActionListener(
new UpButtonListener());
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
65
Example
• When the Up button is clicked with the mouse, the
UpButtonListener object's actionPerformed()
method is invoked, and passed a reference to the
ActionEvent object for the event
• In this example, when you click the button, "Up
button clicked" is displayed
• We can write similar event listener classes for the
Down and Reset buttons, then verify that the program
correctly recognizes input from the user (although the
listeners currently don't do any useful work - that's
next)
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
66
33
MVC Controller
• When structuring a Java program according to the
MVC pattern, the controller corresponds to the
listener classes, plus the code that registers the
listeners with the components
• The controller for the Counter app. will consist of four
classes:
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
67
Counter App Controller Classes
• The listener for the Up button will be an instance of a
class called UpButtonListener
• The listener for the Down button will be an instance
of a class called DownButtonListener
• The listener for the Reset button will be an instance
of a class called ResetButtonListener
• We'll also have a class called CounterController
that will be responsible for creating the listener
objects and registering them with the appropriate
JButton objects
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
68
34
Counter App Controller Classes
• Controller classes often need to use components
created by the view class(es); e.g.,
– to register a listener with a component
– to get input from a component; e.g., the
keystrokes that were typed in a JTextField
• We could pass references to the component objects
to the controller class constructors , or the view
classes could provide getter methods that return
references to its components
• There's a better way... use inner classes
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
69
Inner Classes
• An inner class is a class defined inside another class
• An instance of an inner class can access the
variables of the instance of the enclosing class that
created it
• The 3 listener classes will be defined as private inner
classes within CounterController
• CounterController will be defined as a private
inner class within CounterView
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
70
35
CounterController
private class CounterController
{
private CounterModel model;
public CounterController(CounterModel model) {
this.model = model;
upButton.addActionListener(
new UpButtonListener());
downButton.addActionListener(
new DownButtonListener());
resetButton.addActionListener(
new ResetButtonListener());
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
71
CounterController
/* The listener that is invoked when
the Up button is clicked. */
private class UpButtonListener implements
ActionListener
{
public void actionPerformed(
ActionEvent e) {
model.increment();
}
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
72
36
CounterController
/* The listener that is invoked when the
Down button is clicked. */
private class DownButtonListener implements
ActionListener
{
public void actionPerformed(
ActionEvent e) {
model.decrement();
}
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
73
CounterController
/* The listener that is invoked when the
Reset button is clicked. */
private class ResetButtonListener
implements ActionListener
{
public void actionPerformed(
ActionEvent e) {
model.reset();
}
}
}
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
74
37
Changes to CounterView
• This class is now responsible for creating the
controller:
public class CounterView extends JFrame
{
...
public CounterView(CounterModel model) {
...
contentPane.add(buttonPanel,
BorderLayout.CENTER);
/* Create the listeners for the buttons. */
new CounterController(model);
}
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
75
Updating the View
• We know have a prototype that has a GUI and which
requests the model to change its state when the user
clicks the GUI's buttons
• Now we need to arrange for the view to be updated
when the model's state changes
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
76
38
Updating the View
:CounterModel
:CounterView
increment()
getCounterDisplay()
getDownButton()
Model gets components
from view, updates
JTextField with current
count, enables Down JButton.
POOR APPROACH - WHY?
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
77
Updating the View
:CounterModel
:CounterView
increment()
giveCurrentValue()
Model gives current state
to view, view updates its
components.
O.K. HERE, BUT
GENERALLY A
POOR APPROACH - WHY?
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
78
39
Updating the View
:CounterModel
:CounterView
increment()
update()
value()
Model asks view to update
itself, view ask model for
the state information that
it wants to display.
BEST APPROACH SO FAR,
BUT HAS A FEW
LIMITATIONS
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
79
Observer Pattern
• This is a common problem, and one of the best
solutions is described a design called the Observer
pattern
– you'll study design patterns extensively in upper
year courses
• Intent
– “Define a one-to-many dependency between
objects so that when one object changes state, all
its dependents are notified and updated
automatically.”
-- Design Patterns:Elements of Reusable Object-Oriented Software
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
80
40
The Problem
• We need to define a one-to-many dependency
between the model and one or more views so that
when the model changes its state all its dependents
are notified and updated automatically
• We want to notify the views:
– without having to know how many there are
– without having to know who they are
• Essentially, we want to remove the tight coupling
between the model object(s) and the view object(s)
that should be notified
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
81
Essence of the Solution
• The Observer pattern proposes a general design
solution describing how to establish the relationships
between these objects
• The pattern defines a subject and observers
– each subject maintains a list of dependent
observers
– when a subject changes state, all of its observers
are notified
– in response to receiving a notification, each
observer queries the subject so that it can update
its state
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
82
41
Essence of the Solution
• This pattern is a publish-subscribe mechanism:
– subject publishes notifications
– observers subscribe (register with the subject) to
receive these notifications
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
83
GOF Observer Pattern Structure
Subject
1
attach(anObserver)
detach(anObserver)
notify
ConcreteSubject
- subjectState
getState
setState
*
Observer
update
for all o in observers {
o.update()
}
ConcreteObserver
- observerState
update
observerState =
subject.getState()
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
84
42
Classes in the Observer Pattern
• Participants (adapted from GoF)
• Subject
– knows its observers. Any number of Observer
objects may observe a Subject
– provides an interface for attaching and detaching
Observer objects
• Observer
– defines an updating interface for objects that
should be notified of changes in a subject
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
85
Classes in the Observer Pattern
• ConcreteSubject
– stores state of interest to ConcreteObserver
objects
– sends a notification to its observers when its state
changes
• ConcreteObserver
– maintains a reference to a ConcreteSubject object
– stores state that should stay consistent with the
subject’s
– implements the Observer updating interface to
keep its state consistent with the Observable
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
86
43
Java Support for the Observer Pattern
• Java directly supports the Observer pattern through
class java.util.Observable and interface
java.util.Observer
• An observer (e.g. a view) implements the Observer
interface
• A subject (e.g., the model) extends the Observable
class
• The method names are different than those shown in
the class diagram, but they provide equivalent
operations
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
87
Modifying CounterModel
public class CounterModel extends Observable
{
private int count;
public CounterModel() {
count = 0;
}
public void increment() {
count++;
setChanged();
notifyObservers();
}
Inherited from
class Observable
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
88
44
Modifying CounterModel
public void decrement() {
if (count > 0)
count--;
setChanged();
notifyObservers();
}
public void reset() {
count = 0;
setChanged();
notifyObservers();
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
89
Modifying CounterModel
public int value { return count; }
public String toString() {
return Integer.toString(count);
}
public boolean equals(Object o) {...}
}
• IMPORTANT: Notice that all methods that change
the model's state invoke setChanged() and
notifyObservers(), but methods that don't
change the state never invoke those methods
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
90
45
Modifying CounterView
import java.awt.*;
import javax.swing.*;
public class CounterView extends JFrame
implements Observer
{
• The Observable interface defines a single abstract
method:
public void update(Observable o, Object arg);
• We must implement the update() method to update
the view to reflect the changed state of the model
• This method will be invoked when the model invokes
setChanged()/notifyObservers()
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
91
Modifying CounterView
public void update(Observable o, Object arg) {
/* Currently, the CounterModel we're observing
* doesn't pass an argument when it notifies
* its observers, so we don't use arg in this
* method.
*/
CounterModel model = (CounterModel)o;
/* Update the text field with the current
* value of the counter.
*/
int count = model.value();
counterDisplay.setText(
Integer.toString(count));
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
92
46
Modifying CounterView
/* Ensure that the Down button is enabled
* only when the count is positive.
*/
if (count == 0)
downButton.setEnabled(false);
else
downButton.setEnabled(true);
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
93
Modifying CounterView
• How does the model know which view or views are
observing it?
• We need to change CounterView() to register the
view as an observer of the model
...
contentPane.add(buttonPanel,
BorderLayout.CENTER);
/* Register this view as an observer of the
* model.
*/
model.addObserver(this);
/* Create the listeners for the buttons. */
new CounterController(model);
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
94
47
Modifying Class Counter
• The main() method should ask the view to update
itself after the model, view and controller have been
created
public class Counter
{
public static void main(String[] args) {
CounterModel model = new CounterModel();
CounterView view = new CounterView(model);
view.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE);
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
95
Modifying Class Counter
/* Update the view to reflect the initial
* state of the model.
*/
view.update(model, null);
view.setResizable(false);
view.pack();
// or view.setSize(400, 300);
view.setVisible(true);
}
}
• Also, notice the use of pack() instead of
setSize() to size the frame
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
96
48
Tracing Key Method Invocations
Counter
<<create>>
: CounterView
addObserver(this)
: CounterModel
<<create>>
: CounterController
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
97
Tracing Key Method Invocations
: UpButtonListener
: CounterModel
: CounterView
actionPerformed()
increment()
notifyObservers()
update()
value()
setText()
setEnabled()
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
98
49
Handling Events From Multiple Sources
• A single event listener object can be registered as the
listener for several components
• To handle the event, the listener must first identify
which component sent the event
• The event listener starts by sending the event object
the getSource() message, which returns a
reference to the object that generated the event
• Let’s look at how to write an event listener that
handles the 3 counter buttons
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
99
CounterController with 1 Listener (v1)
private class CounterController
{
private CounterModel model;
public CounterController(CounterModel model) {
this.model = model;
ActionListener listener =
new CounterButtonListener();
upButton.addActionListener(listener);
downButton.addActionListener(listener);
resetButton.addActionListener(listener);
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
100
50
CounterController with 1 Listener (v1)
/* The listener that is invoked when the Up,
* Down and Reset buttons are clicked.
*/
private class CounterButtonListener
implements ActionListener
{
public void actionPerformed(ActionEvent e) {
/* Get a reference to the component that
* sent the event.
*/
Object o = e.getSource();
JButton b = (JButton)o;
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
101
CounterController with 1 Listener (v1)
if (b == upButton)
model.increment();
else if (b == downButton)
model.decrement();
else if (b == resetButton)
model.reset();
}
}
Notice that we use ==, not equals().
Why?
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
102
51
CounterController with 1 Listener (v1)
• In this example, b is a reference to the JButton
object that generated the event
• This reference is compared to the references saved
in instance variables upButton, downButton, and
resetButton
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
103
CounterController with 1 Listener (v2)
• Another way we can identify which button was clicked
is to check action commands
• Each button has an action command, which is a
String
• By default, this action command is the button’s label,
but this can be changed by sending the button the
setActionCommand() message
• We can obtain the action command by invoking
JButton’s getActionCommand() method, which
returns the String
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
104
52
CounterController with 1 Listener (v2)
private class CounterController
{
private CounterModel model;
public CounterController(CounterModel model) {
this.model = model;
ActionListener listener =
new CounterButtonListener();
upButton.addActionListener(listener);
downButton.addActionListener(listener);
resetButton.addActionListener(listener);
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
105
CounterController with 1 Listener (v2)
/* The listener that is invoked when the Up,
* Down and Reset buttons are clicked.
*/
private class CounterButtonListener
implements ActionListener
{
public void actionPerformed(ActionEvent e) {
/* Get a reference to the component that
* sent the event.
*/
Object o = e.getSource();
JButton b = (JButton)o;
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
106
53
CounterController with 1 Listener (v2)
String s = b.getActionCommand();
if (s.equals("Up"))
model.increment();
else if (s.equals("Down"))
model.decrement();
else if (s.equals("Reset"))
model.reset();
}
}
Notice that we use equals(), not ==.
Why?
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
107
CounterController with 1 Listener (v3)
• The drawback to this approach is that every time we
change the button labels (e.g., to use a different
alphabet in a different country), the action commands
will change
• Use setActionCommand() to change the action
commands
– changing an action command doesn't change the
button's label
• Example:
upButton.setActionCommand("+");
downButton.setActionCommand"("-");
resetButton.setActionCommand("0");
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
108
54
CounterController with 1 Listener (v3)
private class CounterController
{
private CounterModel model;
public CounterController(CounterModel model) {
this.model = model;
ActionListener listener =
new CounterButtonListener();
upButton.addActionListener(listener);
downButton.addActionListener(listener);
resetButton.addActionListener(listener);
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
109
CounterController with 1 Listener (v3)
/* The listener that is invoked when the Up,
* Down and Reset buttons are clicked.
*/
private class CounterButtonListener
implements ActionListener
{
public void actionPerformed(ActionEvent e) {
/* Get a reference to the component that
* sent the event.
*/
Object o = e.getSource();
JButton b = (JButton)o;
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
110
55
CounterController with 1 Listener (v3)
String s = b.getActionCommand();
if (s.equals("+"))
model.increment();
else if (s.equals("-"))
model.decrement();
else if (s.equals("0"))
model.reset();
}
}
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
111
Using Action Commands
• Changing the counter controller to use action
commands as the way to identify the button is a bit
contrived, but for more complicated GUIs, they are a
useful way to provide information about the button to
the event listener
SYSC 1101 - Building GUIs with Java: Introduction to AWT & Swing
112
56