presentation source

Download Report

Transcript presentation source

GSAMS’
Undistinguished
Lecture Series
presents . . .
Graphical User Interfaces:
Applets, Graphical
Applications,
Events & Interfaces
Lecture Contents
• GUIs and the Java AWT
– “Graphical User Interfaces” / “Abstract
Windowing Toolkit”
• Components as elements of presentation
and interaction
• Composition of UIs with containers of
components
• Layout of components within containers
• Interaction with GUIs through eventdriven programming
Graphical User Interface (GUI)
• The name for one variety of “user interface” (UI).
• An interface in which the user interacts with objects
on the screen (icons, buttons, scroll-bars, etc.) via
mouse clicks or keyboard actions. (Expressed in the
Seeheim model.)
• Popularized in 1980s by the Macintosh.
•Now state of the practice, and not final word in UI
•Replaced text-based “command line”
and “function key” interfaces.
•Despite similarities, GUIs are typically
platform-specific (Windows 95/98/NT,
MacOS, Xt, NeWS)
The AWT
(Abstract Windowing Toolkit)
• How Java implements a platform-independent GUI
(Graphical User Interface) on different platforms.
• API to the JVM’s “virtual” user interface
• Java 1.0 & 1.1 GUIs were quite bland because of the
need to be platform-independent.
• Related: Java 1.2’s “Swing” classes
create fully-functional GUIs for Java
Steps to GUI Construction
In Java, to create a GUI, you (1):
• Specify a Container, using . .
.
• a Layout Manager to . . .
• place Components and/or
Containers of Components .
..
• on the screen as desired.
In Java, to make a GUI act as the interface
for a program, you (2)
• Design human/computer dialog,
using Listeners and componentgenerated events
I.e. UI form and
appearance
I.e. UI interaction
and behavior
Lecture Contents
• GUIs and the Java AWT
– “Graphical User Interfaces” / “Abstract
Windowing Toolkit”
• Components as elements of presentation
and interaction
– Classes of components & the AWT class
hierarchy
– Example declaration & presentation
Java code
• Composition of UIs with containers of
components
• Layout of components within
containers
GUI Components
• Most interactions in a Java GUI are with Components.
• Another generic term for Component in other GUIs (e.g.
X Windows) is "widget".
• Different types of components for different types of
interaction (e.g. buttons, etc.)
•User interactions with components create events (thus,
event-driven programming)
• As a rule, components cannot have
other components added to them
• Exception to rule: pop up menus may
have menu items added to them.
The AWT Component Class Hierarchy
Component
Button
- generic widget that you can interact with
- a widget that you can press
Canvas
- a widget that you can draw on
Checkbox
- a widget that is checked or not checked
Choice
- an option menu that drops down
Container
- a generic class that contains Components
Panel
- a container to be used inside another
container; used to split an existing window
Label
- a single line of read-only text
List
- a list of Strings
Scrollbar
- a horizontal or vertical scrollbar
TextComponent
TextArea - multi-line editable text
TextField - single-line editable text
Components--Examples
Canvas:
• typically a drawing surface on which shapes, graphs,
pictures, etc can be drawn.
• utilize mouse events and mouse motion events to interact
with the user to accomplish the drawing tasks.
TextField:
• a one-line data entry area
• theoretically infinite in length
• can generate Key events to indicate that
the user has typed a key
• more typically, it generates an Action event
when the user finishes the data entry and
hits Return in the TextField.
Components--Examples
Button:
• simply a clickable label-like component
• appears as a standard button on whatever graphical
environment the user happens to be running at the time
• generates an Action event when clicked
Label:
• a one-line field of text.
• user cannot change this text directly; program changes text
with setText( ) method.
• usually not used to capture events (but could)
• usually used as a one-way information source
to provide a message to the user.
GUI Containers
• Containers are special components that may
contain other components with which the user
interacts.
Examples of Containers:
• Panels
• Frames
• Applets
Note: Containment is not the same as
extension.
A Frame may contain buttons,
but buttons are not subclasses of
Frame.
Containers
Containers are components which can have:
• Layouts set on them
• Other components or containers added to them.
The types of containers include:
1. Applet:
• Generally (but not always) embedded in HTML;
• Is automatically created for you as the area of the web
browser or appletviewer in which the applet loads.
A class that extends Applet:
• Is automatically an Applet container,
• Can have a layout set on it and
components/containers added to it.
Containers
2. Frame:
• Represents a window on the screen.
• Can have Menu bars on them for pull-down menus
• Can be positioned on the screen via such methods:
public void setBounds(int x, int y, int width, int height)
public void setLocation(int x, int y);
3. Panel:
• Is intended as a container/component that can be
added to another container's layout to produce an
embedded or multi-level layout.
Clever use of panels and layouts within
the panels can produce professional
and complex interface designs.
Selecting a Container
Common Top-Level Containers:
Frame -- familiar window object with scrollbars, etc.
Window -- more basic window object, no scrollbars, etc.
Applet -- embedded byte code inside HTML document.
Instantiation:
Note: Frames and Windows not self-disposing.
(GUI components use more than just memory: Only memory
is garbage-collected by the JVM. Other resources have to
be reclaimed manually by dispose() )
Frame myFrame = new Frame();
myFrame.setLayout(new FlowLayout());
myFrame.add(myButtonInstance);
...
/* when done */
myFrame.dispose();
/* (event handling to come shortly . . .) */
Containers -- Applets
Special types of containers
-- embedded inside HTML document, between tags:
<HTML>
<APPLET code = “MyApplet.class”
WIDTH = 400 HEIGHT = 300>
</APPLET>
</HTML>
Applets have no main(String arg[]) method
-- supplied by browser instead
-- Applet lifecycle:
public
/*
public
public
public
public
void init ()
a main() ‘substitute’ */
void start ()
void paint (Graphics g)
void stop ()
void destroy ()
Minimum
params;
others
possible
Containers -- Subclassing
import java.applet.Applet;
import java.awt.*;
class myApplet extends Applet {
public void init () {
//define what happens here
}
public void start () {
//define what happens here
}
public void paint (Graphics g) {
//define what happens here
}
public void stop () {
//define what happens here
}
//...etc...
}
Generally:
Applets use
inheritance while
Frames use
composition and/or
inheritance
The Applet ‘Sandbox’ Model
Applet code runs in 'sandbox’ within the VM, with
significant restrictions on what it can do.
This is enforced by the SecurityManager class
Work-arounds for applet security restrictions include
digitally signing code, servlettes, etc.
Applications can similarly invoke
SecurityManager objects
The Applet ‘Sandbox’ Model
Untrusted code cannot:
– Read files (except from host URL)
– List Directories
– Obtain file information (existence, size, date, etc.)
– Write, Delete, Rename files or directories
– Read or write from FileDescriptor objects
– Listen/Accept on any privileged port <= 1024
– Call System.exit() or Runtime.ext()
– Create new processes with Runtime.exec()
– Start a print job, access clipboard or event queue
Get full access to System.getProperty(), but it can
use getProperty() to find:
java.version, java.class.version, java.vendor,
java.vendor.url, os.name, os.version
os.arch, file.separator, path.separator,
line.separator
Remaining
weak-spot:
Denial of
Service
Attacks
Applet Example
/**
*
* ReadsFromURL.java -- a trivial applet demonstrating
*
how to read server-side data via a URL stream
*
* The applet also uses heavyweights, causing
* slow redraws
*
*/
import java.awt.*; import java.applet.*;
import java.net.*; import java.io.*;
public class ReadsFromURL extends Applet {
protected URL fileURL;
protected String result;
protected TextArea ta;
protected int off = 15;
/**
* Default constructor
*
*/
public ReadsFromURL() {
// default constructor for some fussy VMs
}
/**
* initialize the applet
*
* @see#readInURL() -- called to initialize data
*/
public void init(){
setBackground(Color.lightGray);
ta = new TextArea();
ta.setFont(new Font("Courier",
Font.BOLD, 12));
/*
* Set server to read applet source code
*/
try {
fileURL = new URL
(getCodeBase() + "/ReadsFromURL.java");
}
catch(MalformedURLException e){
showStatus("Error!");
}
/*
* Layout the container
*/
this.setLayout(null); // necessitates setBounds()
add(ta);
ta.setBounds(getSize().width/8,
getSize().height/8,
getSize().width*3/4,
getSize().height*3/4);
readInURL();
}// init
/**
*
*
*
*/
paint the applet, including borders, bevels, and
screws
public void paint(Graphics g) {
// bevels
for (int w=0; w<getSize().width; w+=12) {
for (int h=0; h<getSize().height; h+=12) {
g.setColor(Color.white);
g.drawLine(w,h,w+1,h);
g.drawLine(w+1,h,w+5,h+4);
g.drawLine(w+8,h+10,w+12,h+6);
g.drawLine(w+12,h+6,w+13,h+6);
g.setColor(Color.darkGray);
g.drawLine(w,h+2,w+5,h+7);
g.drawLine(w+5,h+7,w+6,h+7);
g.drawLine(w+9,h+12,w+13,h+8);
}
}
/* borders */
g.setColor(Color.gray);
g.fillRect(0, 0, getSize().width, off);
g.fillRect(0, 0, off, getSize().height);
g.fillRect(getSize().width-off,0, off,getSize().height);
g.fillRect(0,getSize().height-off, getSize().width, off);
g.fillRect(0,0,2*off, 2*off);
g.fillRect(getSize().width-2*off,0, 2*off, 2*off);
g.fillRect(0, getSize().height-2*off, 2*off, 2*off);
g.fillRect(getSize().width-2*off, getSize().height-2*off,
2*off, 2*off);
int dX, dY; int x1=off; int x2=2*off; int
x3=getSize().width-(1+2*off);
int x4=getSize().width-(1+off);
int y1=off; int y2=2*off;
int y3=getSize().height-(1+2*off);
int y4=getSize().height-(1+off);
g.setColor(Color.black);
g.drawLine(x4,y2,x3,y2);
g.drawLine(x2,y1,x2,y2);
g.drawLine(x1,y2,x1,y3);
g.setColor(Color.white);
g.drawLine(x3,y1,x3,y2);
g.drawLine(x4,y3,x3,y3);
g.drawLine(x3,y4,x2,y4);
g.drawLine(x3,y1,x2,y1);
g.drawLine(x2,y2,x1,y2);
g.drawLine(x2,y3,x2,y4);
g.drawLine(x4,y2,x4,y3);
g.drawLine(x3,y3,x3,y4);
g.drawLine(x2,y3,x1,y3);
//raised outer edge
g.setColor(Color.black);
g.drawRect(0,0, getSize().width-1, getSize().height-1);
g.setColor(Color.white);
g.drawLine(0,0, getSize().width-1,0);
g.drawLine(0,0,0, getSize().height-1);
//screws
for (int x=2;x-->0;){
for (int y=2;y-->0;){
dX=(x==1)?0:x3; dY=(y==1)?0:y3;
g.setColor(Color.white);
g.drawArc(dX+off/2+1,dY+off/2+1,
(int)1.5*off,(int)1.5*off,90,100);
g.drawLine(dX+(int) (1.25*off)+2,
dY+(int) (.75*off),
dX+(int) (.75*off)-1,
dY+(int) (1.5*off)-1);
g.setColor(Color.black);
g.drawOval(dX+off/2,dY+off/2,
(int)1.5*off,(int)1.5*off);
g.drawLine(dX+(int) (1.25*off)+1,
dY+(int) (.75*off)-1,
dX+(int) (.75*off)-2,
dY+(int) (1.5*off)-2);
}
}
}// paint
public void readInURL() {
try {
String strTemp;
java.io.InputStream input =
fileURL.openStream();
BufferedReader buff = new BufferedReader
(new InputStreamReader(input));
while((strTemp = buff.readLine()) != null)
ta.append(strTemp+"\n");
/* Be a good net neighbor and
close the stream! */
buff.close();
}
catch(IOException darn){
showStatus("Exception: " + darn);
}
}// readInURL
}// class ReadsFromURL
The problem
GUI Layout
• How should components be laid out within a container?
• (Why is this a problem? Because platforms may differ in
screen size / resolution)
AWT Solution
• Layout Managers are AWT classes that encapsulate policies for
laying out components in a container
•Can ensure that the arrangement of objects within a window
will remain proportional regardless of changes in window
dimensions.
•Example of general OOD strategy of putting
rules/policies in a coordinator/referee class.
•A layout manager is always associated
with a container
Layout Managers -- Motivation
• One could specify the location of a Component by specific x and
y coordinates. The Component class contains the method
setLocation(int width, int height):
Button myButton = new Button (“Click”);
add(myButton); // adds to whatever ‘this’ container is
myButton.setLocation(25, 75);
NOTE:
Origin 0,0
at top left
Note: Button’s
x and y coordinate
starts from top left
75 pixels down
Click
25 pixels over
Layout Managers -- Motivation
Problems with specifying x, y coordinates for Component:
• Tedious for even mildly complex GUIs.
• Addition of more components requires recalculation of every
component’s x, y coordinate
• If container resizes (e.g., user expands window), calculations
have to be redone!
Solution:
• Position components based on a percentage
of available container size. Or create an
algorithm to place components . . .
But Java already does this for you . . .
Layout Managers -- AWT Based
• Java provides several layout managers.
• We will concentrate here on two of them:
• BorderLayout
• GridLayout
• To tell a container which layout manager to use, invoke the method:
setLayout( );
and specify a type of layout.
For example:
To specify a BorderLayout:
setLayout (new BorderLayout());
LayoutManagers:
Two General Flavors
• One can conceptually divide layout managers
into two types:
– Those that attach constraints to their
components.
– Those that do not.
• What does this mean?
If a manager attaches constraints to a
component, then information
about a component’s location
(e.g., compass points) is
generated with the object.
LayoutManagers: Constraints
NORTH
WEST
CENTER
SOUTH
• BorderLayout specifies constraints
corresponding to compass
regions of a container:
EAST
LayoutManagers: Constraints
• BorderLayout then appends constraint information on all
components, e.g.:
this.setLayout (new BorderLayout());
Button e = new Button (“East”);
Button w = new Button (“West”);
Button n = new Button (“North”);
add(e, “East”); // deprecated
add(“West”, w); // works; deprecated
//add(n, BorderLayout.NORTH); // better
LayoutManagers: Constraints
LayoutManagers: Another Example
import java.awt.*;
import java.applet.*;
public class test extends Applet {
String Compass[] = {"North", "South", "East",
"West", "Center"};
public void init() {
/* ALWAYS call super init! */
super.init();
/* set layout */
setLayout(new BorderLayout());
for (int i = (Compass.length) - 1;
i >= 0; i- -){
Button temp = new Button (Compass[i]);
add (temp, Compass[i]);
} // for loop
} // test
LayoutManager: Example
Giving:
LayoutManager:
No Constraints
• The second type of LayoutManager does not
specify constraints for the objects it holds.
• Examples:
– GridLayout()
– FlowLayout()
• Without constraints, you cannot accurately
predict layout behavior across platforms
LayoutManager: No Constraints
import java.awt.*;
import java.applet.*;
public class test extends Applet {
public void init() {
super.init();
String Labels[] = {"Short", "Short", "Long Label",
"Really Long Label", "Really, really long"};
setLayout(new FlowLayout());
for (int i = (Labels.length - 1); i >= 0; i- -){
Button temp = new Button (Labels[i]);
add (temp);
} // for
} //init
} //class test
LayoutManager: No
Constraints
Giving:
LayoutManager: No
Constraints
And also:
LayoutManager: No
Constraints
• Note:
– Since pixels, fonts and insets vary with each platform,
layout without constraints will vary greatly.
• Lesson:
– Use layout managers without constraints only when you
have one or few components
LayoutManager: No
Constraints
• Don’t think that layout managers without
constraints are not useful!
• One of the most useful constraint-free layout
manager is “GridLayout”.
public GridLayout();
public GridLayout(int rows, int cols);
public GridLayout(int rows, int cols,
int hgap, int vgap);
GridLayout
GridLayout specifies a grid pattern via:
setLayout (new GridLayout (rows, columns));
For example:
setLayout (new GridLayout(2,3));
generates:
GridLayout
• To add components (or containers) to a GridLayout, particular
locations are not specified (unlike BorderLayout).
• Instead, the components (or containers) are positioned by the
sequence in which they are added, as indicated by numerals
below.
1
4
2
3
5
6
GridLayout
Optionally, two additional parameters may be used with
GridLayout to specify the horizontal and vertical spacing
(in pixels) between grid elements:
setLayout (new GridLayout (rows, columns, hspace, vspace));
where hspace specifies horizontal size,
and vspace specifies vertical size, e.g.,
setLayout (new GridLayout (2, 2, 7, 5));
GridLayout: Example
import java.awt.*;
import java.applet.*;
public class test extends Applet {
public void init() {
super.init();
setLayout(new GridLayout(4,3,5,5));
int off[]={-2,2,0};
for (int i=9; i >= 1; i--)
// this is “clever” but hard to grok
// thus, is ill-advised:
add (new Button (""+(i+off[i%3])));
add (new Button ("."));
add (new Button ("0"));
add (new Button ("+/-"));
add (new MyPanel(null));
}// init
}//test
GridLayout: Example
Giving:
A Layout Example
Imagine that we wish to create an Applet with the following
interface layout . . .
Label One
TextArea1 is here
{no label displayed}
Label Two
Label 3
Button One
Label Four
Button Two
Button Three
(dotted lines do not really appear; shown for reference)
A Layout Example
Because this is an Applet, the entire layout is defined in
the init( ) method of the Applet.
Doing this implies three activities:
• Sketching the layout on paper.
• Declaring instance variables of the visible components.
• Arranging the components as appropriate using a
combination of nested containers.
A Layout Example
Step One: Sketching the layout on paper
As shown on earlier slide.
Step Two: Declaring instance variables
of the visible components:
TextArea TextArea1 = new TextArea( );
Label Label1 = new Label ("Label One");
Label Label2 = new Label ("Label Two");
Label Label3 = new Label ("Label 3");
Label Label4 = new Label ("Label Four");
Button Button1 = new Button ("Button One");
Button Button2 = new Button ("Button Two");
Button Button3 = new Button ("Button 3");
A Layout Example
Step Three: Arranging the components
using nested containers:
• Consider the overall design in terms of one or more Layout
Managers (for this example, GridLayout is sufficient).
• The Applet itself is a container. Begin there, and create
appropriate subdivisions of screen space:
• For this design, the main container is split into 4 quadrants,
each of equal size.
• This suggests a grid layout on the Applet, with
2 rows and 2 columns, i.e.,
setLayout (new GridLayout (2,2));
A Layout Example
The first quadrant of the GridLayout:
• Contains a Text Area component.
• To allocate the instance variable TextArea1 to the first
quadrant, simply add it first:
add (TextArea1);
Label One
TextArea1 is here
{no label displayed}
Label Two
Label 3
Button One
Label Four
Button Two
Button Three
The second quadrant of the GridLayout:
• Contains two Labels.
• Since we can have only one container or component per area,
we subdivide the quadrant into two areas.
• To do so, we declare a new Panel, then divide it as two areas,
one for each Label:
// create new panel
Panel Panel1 = new Panel();
Label One
TextArea1 is here
{no label displayed}
Label Two
// add it to GridLayout
// at next position
add (Panel1);
Label 3
Button One
Label Four
// subdivide Panel1
// as 2 rows, 1 column
Panel1.setLayout (new GridLayout (2,1));
// add the first two Labels
Panel1.add (Label1); // 1st area: row 1
Panel1.add (Label2); // 2nd area: row 2
Button Two
Button Three
The third quadrant of the GridLayout:
• Contains nothing.
• To "skip a space" in a GridLayout, we
add a "throw-away" panel:
add (new Panel());
Label One
TextArea1 is here
{no label displayed}
Label Two
Label 3
Button One
Label Four
Button Two
Button Three
The fourth quadrant of the GridLayout:
• Contains several components.
• Because only one component is permitted per area, we
subdivide the space as needed:
// create a second Panel
Panel Panel2 = new Panel();
Label One
TextArea1 is here
{no label displayed}
Label Two
// add it to the next position
add (Panel2);
// divide it into 4 rows, 1 column
Panel2.setLayout
(new GridLayout (4,1));
// add the componets, row by row
Panel2.add (Label3);
Panel2.add (Button1);
Panel2.add (Label4);
But Panel 2’s 4th row holds two items, so . . .
Label 3
Button One
Label Four
Button Two
Button Three
The fourth quadrant (continued):
Create room for Button2 and Button3 by:
• creating a new Panel3,
• then adding it to Panel2,
• then subdividing Panel3 into 1
row of 2 columns:
Label One
TextArea1 is here
{no label displayed}
Label Two
// create the new Panel3
Panel Panel3 = new Panel();
// add Panel3 to Panel2
Panel2.add (Panel3);
// subdivide Panel3
// into 1 row, 2 columns
Panel3.setLayout
(new GridLayout (1,2));
// add the Buttons to Panel3
Panel3.add (Button2);
Panel3.add (Button3);
Label 3
Button One
Label Four
Button Two
Button Three
The final code:
// declaration section - usually instance variables
TextArea TextArea1 = new TextArea();
Label Label1 = new Label ("Label One");
Label Label2 = new Label ("Label Two");
Label Label3 = new Label ("Label 3");
Label Label4 = new Label ("Label Four");
Button Button1 = new Button ("Button One");
Button Button2 = new Button ("Button Two");
Button Button3 = new Button ("Button 3");
Panel Panel1 = new Panel();
Panel Panel2 = new Panel();
Panel Panel3 = new Panel();
// set up the layout (inside a constructor or init( ))
setLayout (new GridLayout (2,2));
// quadrant 1 - just a textarea.
add (TextArea1);
// quadrant 2 - panel with two labels
add (Panel1);
Panel1.setLayout (new GridLayout (2,1));
Panel1.add (Label1);
Panel1.add (Label2);
// quadrant 3 - empty and not used
add (new Panel());
// quadrant 4 - Panel containing 4 rows, last of which
// is a Panel containing two buttons
add (Panel2);
Panel2.setLayout (new GridLayout (4,1));
Panel2.add (Label3);
Panel2.add (Button1);
Panel2.add (Label4);
Panel2.add (Panel3);
Panel3.setLayout (new GridLayout (1,2));
Panel3.add (Button2);
Panel3.add (Button3);
Lecture Summary
• GUIs and the Java AWT
• Components as elements of presentation and interaction
• Composition
• Layout of components within containers
– Layout managers encapsulate layout policy
• Containers “delegate” this responsibility.
– Border layout fits elements close to edges/center
– Grid & flow layouts layout spatially if there’s room
– For “clustered” components, use panels
as sub-containers
• components arranged in panels,
arranged in panels, in panels...
GSAMS--Java Course
Interfaces &
Events
Java Interfaces
Java Interfaces
• Multiple inheritance issues
• Adding functionality to a hierarchy
• Adding functionality and a shared
interface to multiple hierarchies
• Using interfaces as types
Event-driven Programming
• Basic model
• Applets
• Events
• Handling Events
• Registering Event Handlers
• Writing Event Handlers
• Debugging Strategies
Java Interfaces
Means of solving many problems that
seem to call for multiple inheritance.
Example:
Want to draw Shapes on a Graphics object.
Drawable
Object
Shape
Circle
Rectangle
Square
Multiple inheritance:
• Introduces many annoying complexities.
• Java does not support it.
Triangle
Java Interfaces--Partial Solution #1
• We could make a new base class
(e.g., DrawableShape), giving us both:
DrawableShape
DrawableCircle
DrawableRectangle
DrawableTriangle
DrawableSquare
and:
Shape
Circle
Rectangle
Square
• Bad idea: much redundancy, is anti-OO.
Triangle
Java Interfaces--Partial Solution #2
• We could insert a new class into the
object hierarchy . . .
Object
Drawable
Shape
Circle
Rectangle
Triangle
Square
• Bad idea: Drawable need not be a propertyof Shapes, are
imposing functionality where it might not be needed.
Java Interfaces
Best: create interface that allow us to extend
functionality without disturbing class hierarchies . . .
Object
Makes our diagram
more complex, but makes
everything else simpler!
Shape
Rectangle
Circle
Triangle
Square
Drawable
DrawableRectangle
DrawableCircle
DrawableSquare
DrawableTriangle
Java Interfaces
Example: add functionality without disturbing existing Shape
hierarchy, e.g., make our existing Squares drawable.
public interface Drawable {
// no constructors! no default methods! just method headers!
public void drawMe (Graphics g);
} // of Drawable
public class DrawableSquare extends Square implements Drawable {
// "extends": we inherit everything that Square has - no need to
// re-write any constructors, accessors, modifiers;
// “implements”: must have code for drawMe( ) (or at least
// declare it as abstract) in order to satisfy interface requirements
public void drawMe (Graphics g) {
g.drawRect (0,0,iSideSize,iSideSize);
} // of drawMe
} // of DrawableSquare
Java Interfaces
• Do just what they say: provide interfaces.
• Typically concerning shared logical properties.
• Can use to provide shared interface/functionality
to multiple independent class hierarchies.
• Typically, interface identifiers end in -able or -ible:
- Drawable
- Printable
- Edible
- Purchasable
Graphics
TextFile
PrintableGraphics
PrintableText
Printable
Interface Example
public interface Printable{
public void printMe( );
} // of interface
public class PrintableText extends TextFile implements Printable{
// inherits from TextFile
// must have printMe( ) method to implement Printable
public void printMe( ) {
// code to print the text file goes here
} // printMe
} // PrintableText
public class PrintableGraphics extends Graphics implements Printable {
// inherits from Graphics
// must have printMe( ) method to implement Printable
public void printMe( ) {
// code to print the Graphics object goes here
} // printMe
} // PrintableGraphics
Interface Example
• Can now use Printable as a type, e.g., . . .
• Can implement a PrinterQueue as an array
of Printables:
Printable[ ] printerQueue = new Printable[10];
• The array printerQueue can now handle
anything that implements the Printable
interface.
• This is an example of polymorphism at work.
Interface Details
Syntax notes re: interface methods:
• They must be public (cannot be private or protected).
• They must be instance methods (cannot be static).
• They are abstract by default (no need to explicitly declare
them to be abstract).
• No variables may be inherited from interfaces.
Java Interfaces
Are independent from class hierarchies.
Can now consider both:
• Are you a <ClassName>?
• Can you do <Functionality>?
Use interfaces when:
• you want to factor out commonalities
among classes, but
• you do not want a relationship between
those classes.
Example Interface:
Enumeration
• Enumeration is an interface, not a class.
• Implemented by class Vector and others (e.g. Hashtable).
• May be implemented by any other classes which are defined
to implement it (e.g., linked list, BST, graph, etc.).
• The interface specifies that all classes which implement
Enumeration must implement the two methods:
public boolean hasMoreElements( );
public Object nextElement( );
Example Interface: Enumeration
• Defines methods needed to enumerate (or iterate through) a set
of values.
• Typically, use methods in a loop to see if there’s another
element to return and, if so, to return a reference to it.
Makes no promises about the order in which elements are
encountered.
• Values may be iterated through only once; there is no way to
reset to the beginning.
Event Driven Programming
Traditional programming:
• The program’s main algorithm governs the flow of control
throughout the program
• The general model:
“do step A, then do step B, then do C or D, then…”
Event-driven programming:
• The program waits for the user to do something, processes that
event, then waits for the user again.
• The general model:
loop
get user event
process user event
do something that responds
to that event
endloop
Event Driven Programming: Applet Example
• A type of event-driven programming.
• A type of application that uses graphics.
An applet:
• Waits for the user to do something, e.g.,
• move the mouse
• click the mouse
• press a key
• Processes that event
• Does something based on that event
For example:
• the program waits until you press a button,
• the program sees that you pressed a button,
• the program then does something based on the fact that
you pressed that button, e.g.,
• clear the screen
• restart a game
Event Driven Programming: Applet Example
Recall the specific stages in an applet’s lifecycle.
• public void init( )
Called by browser or applet viewer: tells applet that it has been
loaded into the system. Is called once per applet.
• public void start( )
Called by browser or applet viewer, tells applet to execute.
• public void paint(Graphics g)
Paints the component (draws the component): tells applet
to paint (draw) the contents of a component.
• public void stop( )
Called by browser or applet viewer:
tells it to stop execution.
• public void destroy( )
Called by browser or applet viewer: tells applet that it is
being killed, that it should destroy resources that it has
allocated so that they can be reclaimed for other use.
Events
Package java.awt.event features common event methods:
actionPerformed(ActionEvent) //
//
keyPressed(KeyEvent)
//
keyReleased(KeyEvent)
//
mousePressed(MouseEvent)
mouseDragged(MouseEvent)
mouseEntered(MouseEvent)
Called if an action occurs in the
Component.
Called if a character is pressed.
Called if a character is released.
// Called if the mouse is down.
// Called if the mouse is dragged
// Called when the mouse enters
// component.
mouseExited(MouseEvent)
// Called when the mouse exits the
// component.
mouseMoved(MouseEvent)
// Called if the mouse
// moves (button is up)
mouseReleased(MouseEvent) // Called if the mouse
// button is released.
Handling Events
Any component, such as
• a Button
• a Canvas
• a Menu, etc.
can have events happen to it.
For example, a user can:
• select a menu item from a Menu
• drag the mouse over a Canvas
• type text into a Text Field
• click on a Checkbox
• etc., etc.
To avoid slow-downs in program execution, Java does not
automatically "handle" any of these events . . . unless the
programmer explicitly tells Java to do so.
Handling Events -- How
In order to capture an event, you need to have an appropriate
“event listener".
An event listener is an interface which specifies some eventhandling methods for the particular type of event to be handled.
For example:
an ActionListener specifies the method:
public void actionPerformed(ActionEvent <eventName>)
For a complete listing of the listeners and the methods
they require, refer to p.151 of Java in a Nutshell,
or the java.awt.event.* package.
Registering Event Handlers
• To have Java use the event listener, you must tell Java to do so by
registering the event
• To register a specific event, use addListener methods built into
each component.
For example, a Button or MenuItem has the method:
addActionListener(ActionListener a)
to add an action listener to itself.
• Adding an action listener specifies that, whenever that Button or
MenuItem gets an action event, it will call the method
actionPerformed( ) on all the actionListeners that have
been added to it
• Because interfaces are contracts, Java guarantees
that any class that implements the ActionListener
interface must provide code for actionPerformed( )
Writing Event Handlers
To write an event handler:
• Have a class that implements one or more of the
Listener interfaces.
To "catch" the event:
• Write code for the appropriate event handler
specifying the response to the event.
• Then, register your event handler class with the
addListener method of the component whose event
you want to catch.
Example follows
Writing Event Handlers: Example
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
public class simpleApplet extends Applet implements ActionListener {
Button other, printHello;
Canvas myCanvas;
public void init( ) {
// set up "other" button; have its action event go here
other = new Button( "other" );
other.addActionListener (this);
// set up "printHello" button; action event go here
printHello = new Button( "Print ‘Hello World’" );
printHello.addActionListener (this);
continued
// set up Canvas to draw on
myCanvas = new Canvas( );
// place components on screen
setLayout( new BorderLayout( ) );
add( printHello, "North" );
add( other, "South" );
add( myCanvas, "Center" );
} // init
public void actionPerformed ( ActionEvent evt ) {
// print a simple message to see what button was pressed
// getSource( ) returns a reference to the object that
// caused the event to happen
if ( evt.getSource( ) = = other )
System.out.println( “other pressed.” );
else
System.out.println( “Print 'Hello World' pressed.” );
repaint( );
} // actionPerformed
continued
public void paint( Graphics g ) {
System.out.println( "paint( ) called" );
myCanvas.getGraphics( ).drawString( "painting!", 0, 115 );
myCanvas.getGraphics(
myCanvas.getGraphics(
myCanvas.getGraphics(
myCanvas.getGraphics(
} // paint
} // simpleApplet
).setColor( Color.magenta );
).fillOval( 220, 220, 50, 50 );
).setColor( Color.black );
).drawOval( 220, 220, 50, 50 );
Event Handling: General Options
Four general options for event handling:
1. Event Listeners
-- use interfaces. Good for low-level control.
2. Event Adapters
-- use objects. More selective.
3. Semantic Events
-- for simple event handling.
4. ‘Old’ JDK 1.02 events
--not recommended; useful in rare
circumstances
Option #1: Event Listeners
As noted, one can ‘addXYZListener’ to a component, e.g.:
class TestApplet extends Applet implements MouseListener{
Button myButton;
public void init(){
myButton = new Button(“Click”);
myButton.addMouseListener(this);
...
} // TestApplet
When using listener interfaces, one must code all event methods-even those we are not interested in. Wasted code arises:
“no-op”
methods
Single method we
do something in
public void
public void
public void
public void
mouseEntered(MouseEvent e){;}
mouseExited(MouseEvent e){;}
mouseClicked(MouseEvent e){;}
mouseReleased(MouseEvent e){;}
public void mousePressed
(MouseEvent e){
/* handle mouse event */}
Option #2: Event Adapters
In addition to interfaces, the java.awt.event.* package provides
“adapter” classes that can be subclassed.
No need to code every method; just override the method you need:
Public class EventHandler extends MouseAdapter {
public void
public void
public void
public void
mouseEntered(MouseEvent e){;}
mouseExited(MouseEvent e){;}
mouseClicked(MouseEvent e){;}
mouseReleased(MouseEvent e){;}
public void mousePressed(MouseEvent e){
/* handle mouse event */}
Less wasted code; but you use
up your single inheritance!
Event Adapters: Registration
public class TestApplet extends Applet{
private Button myButton;
private EventHandler handle;
public void init(){
handle = new EventHandler(this);
myButton = new Button(“Click”);
myButton.addMouseListener(this);
.........
public void takeActions() { . . . . }
Passing ‘this’
allows for
call-backs
public class EventHandler extends MouseAdapter{
TestApplet myApplet;
public EventHandler(TestApplet myApplet){
this.myApplet = myApplet ;
}
public void mousePressed(MouseEvent e){
myApplet .takeActions();
Event handled
}
by accessing
applet
Option #3: Semantic Events
The foregoing options (interfaces and objects) involved
low-level events.
Event processing may also occur through the use of semantic
events.
Unlike listeners/adapters, these are high-level, componentbased events.
They essentially ‘funnel’ a variety of low-level events into a
single method.
NOTE: You lose ability to catch small, granular events (e.g.,
mouseEntered/Exited are not possible).
Since ALL events delivered to a few methods,
event handling relies on complex,
linear if/else structures.
Semantic Events
Semantic Event
Components and Firing Event
ActionEvent
Button (activated)
List (double-clicked)
MenuItem (selected)
TextField (typed)
AdjustmentEvent
Scrollbar (moved)
ItemEvent
Checkbox (toggled)
CheckboxMenuItem (selected)
Choice (selected)
List (selected)
TextEvent
TextComponent
(text changes)
(non) Option #4: JDK 1.02 Events
• An earlier version of Java used “boolean” return values
to indicate consumption of events
• Not recommended; still used for some web development
• Do not mix JDK 1.1 and JDK 1.02 event handlers--the
component ceases to function.
• Rare use: JDK 1.02 guarantees which event will arrive
first to a component.
Event Handling Options: How to Decide
Costs
Event Listeners
(interfaces)
Must code all
methods; wasteful
no-ops result
Benefits
Keep all
events in
single class
Event Adapters
(inheritance)
Uses up single
inheritance
opportunity
Good abstraction;
override those
methods
you need
Semantic Events
Simplifies
event handling
Loss of
granular
control;
linear code
Debugging re: Event Handlers
• Debugging an event-driven program (whether applet or graphical
application) is more tricky than debugging a non-event-driven
program.
• With an event-driven Java program, you don't explicitly code any
kind of event-handling loop that "polls" for occurring events, then
calls the appropriate handler(s) for those events.
• Instead, the Java internals handle this polling action for you.
Debugging becomes trickier because now you have to make sure
that your event handling code works correctly.
• You also have to make sure you're handling the
correct events in the first place! For example,
your code for mouseEntered( ) may work perfectly,
but if you're expecting it to get called when the
user clicks a mouse button, it won't be!
Debugging re: Event Handlers
So, in debugging event-driven programs written
with Java, the steps are:
• Be sure you're handling the appropriate events:
Map out on paper what events get thrown from what
components, and what class(es) handle them.
• Handle the events appropriately:
This is the kind of debugging you're already familiar with:
Once you're sure the appropriate events
are getting handled, the rest is being sure
the event-handling code (and the code that
the event handlers call) work.
Example: Create a Paint Applet
Goal: create applet that:
Allows user to draw
with mouse
Mouse drag draws
Mouse up stops drawing
Pen color selectable
Button to clear canvas
Will show three versions,
each using different event
handling techniques
CLEAR
PenColor:
Red
Design #1: Interfaces Only
1. List Basic
Components/Containers:
java.applet.Applet
--java.awt.Canvas
--java.awt.Panel
---java.awt.Button
---java.awt.Choice
---java.awt.Label
2. List Basic Behaviors:
mouse drag draws
button clears canvas
choice changes pen color
canvas knows whether to
draw (mouse drag) or
not (mouse is up)
Design #1: Interfaces Only
3. Outline classes, assigning
from two lists
a. Drawing: Canvas subclass
-- paint method draws
-- has reference to controls
-- boolean flags for clear/draw
b. Control panel: Panel subclass
-- has Button, Label, Choice
-- sets flags in canvas to clear/
change color, etc.
-- has reference to canvas
c. Top container: Applet subclass
-- BorderLayout
-- Introduces classes to each
other
-- Sets some initial values
General Layout
Applet (BorderLayout)
-- add Canvas to CENTER
-- add ControlPanel to SOUTH
-- set initial values (size of
CANVAS
canvas, pen color)
ControlPanel (GridLayout)
Widgets (Button,
Label, Choice)
Design #1: Class Structure
MANDATORY: Plan your
cross-class communications
In this version, events are
handled by a Control Panel
In such a case, how to send
Q:
events to Canvas?
A: Cross-class
communications!
The control panel has a reference
to the DrawCanvas, and the canvas
has a reference to the ControlPanel
instance (ver #1).
Alernatively (ver #2), both have
reference to Applet, which provides
reference to components
DrawApplet Class Structure
DrawApplet
Applet subclass
DrawCanvas
Canvas subclass
boolean flags for
clear, drawing
calls (ver #1)
ControlPanel
Panel Subclass
Button to clear
choice to change pen color
import java.applet.Applet;
import java.awt.*;
public class DrawApplet extends Applet {
private ControlPanel controls;
private DrawCanvas canvas;
public void init() {
this.setLayout(new BorderLayout());
canvas = new DrawCanvas( (int) (getSize().width *.75),
(int) (getSize().height *.75) );
controls = new ControlPanel();
/* introduce the components to each other */
canvas.setControls(controls);
controls.setCanvas(canvas);
canvas.setColor(Color.red);
add(canvas, BorderLayout.CENTER);
add(controls, BorderLayout.SOUTH);
} // init
}// class DrawApplet
import java.awt.*;
import java.awt.event.*;
public class ControlPanel extends Panel implements MouseListener,
ItemListener {
private DrawCanvas canvas;
private Button clearButton;
private Label label;
private Choice colorChoice;
public ControlPanel() {
this.setLayout(new GridLayout(1, 3));
clearButton = new Button("Clear");
label = new Label("Select Pen Color:");
colorChoice = new Choice();
colorChoice.add("Red"); colorChoice.add("Blue");
colorChoice.add("Green");
colorChoice.addItemListener(this);
clearButton.addMouseListener(this);
add(clearButton); add(label); add(colorChoice);
} // constructor
public void setCanvas(DrawCanvas canvas) {
this.canvas = canvas;
} // setCanvas
/* class ControlPanel (cont’d) . . . */
public void mousePressed(MouseEvent e) {
if (e.getSource() == clearButton) {
canvas.setClear(true);
canvas.repaint();
} // if
} // mousePressed
public void itemStateChanged
(ItemEvent e) {
int index =
colorChoice.getSelectedIndex();
switch(index) {
case 0://red
canvas.setColor(Color.red); break;
case 1: // blue
canvas.setColor(Color.blue); break;
case 2:
canvas.setColor(Color.green);
break;
} // switch (what’s wrong with it?)
} // itemStateChanged
/* wasted code */
public void mouseReleased (MouseEvent e){
;
} // mouseReleased
public void mouseClicked (MouseEvent e){
;
} // mouseClicked
public void mouseExited (MouseEvent e){
;
} // mouseExited
public void mouseEntered (MouseEvent e){
;
} // mouseEntered
}// class ControlPanel
import java.awt.*;
import java.awt.event.*;
public class DrawCanvas extends Canvas
implements MouseMotionListener, MouseListener{
private int mouseX, mouseY, oldX, oldY;
private boolean bClear, bDrawing;
private Color color;
private ControlPanel controls;
public DrawCanvas(int width, int height) {
this.setSize(width,height);
this.addMouseListener(this);
this.addMouseMotionListener(this);
} // constructor
public void setControls(ControlPanel controls) {
this.controls = controls;
} // setControls
public void updateCoordinates(MouseEvent e) {
updateCoordinates(e.getX(), e.getY());
} // updateCoordinates
/* class DrawCanvas (cont’d) . . . */
public void updateCoordinates(int x, int y) {
oldX=mouseX; oldY = mouseY;
mouseX=x; mouseY=y;
repaint();
} // updateCoordinates
public void setDrawing(boolean bDrawing) {
this.bDrawing = bDrawing;
} // setDrawing
public void setClear(boolean bClear) {
this.bClear = bClear;
} // setClear
public boolean getDrawing() {
return bDrawing;
} // getDrawing
public boolean getClear() {
return bClear;
} // getClear
/* class DrawCanvas (cont’d) . . . */
public Color getColor() {
return color;
} // getColor
public void setColor(Color color) {
this.color = color;
} // setColor
public void update(Graphics g) {
paint(g);
} // update
public void paint (Graphics g) {
if (getClear()) {
g.setColor(Color.white);
g.fillRect(0,0,getSize().width,
getSize().height);
setClear(false);
} // if
if (getDrawing()) {
g.setColor(getColor());
g.drawLine(oldX, oldY, mouseX, mouseY);
} // if
} // paint
/* class DrawCanvas (cont’d) . . . */
public void mouseMoved(MouseEvent e) {
updateCoordinates(e);
} // mouseMoved
public void mouseDragged
(MouseEvent e){
updateCoordinates(e);
repaint();
} // mouseDragged
public void mouseEntered(MouseEvent e) {
updateCoordinates(e);
} // mouseEntered
/* below is wasted code */
public void mouseClicked
(MouseEvent e){
} // mouseClicked
public void mousePressed(MouseEvent e) {
setDrawing(true);
updateCoordinates(e);
repaint();
} // mousePressed
public void mouseExited
(MouseEvent e){
} // mouseExited
}// class DrawCanvas
public void mouseReleased
(MouseEvent e) {
setDrawing(false);
updateCoordinates(e);
repaint();
} // mouseReleased