Frames on the Screen

burgerraraΛογισμικό & κατασκευή λογ/κού

18 Νοε 2013 (πριν από 3 χρόνια και 9 μήνες)

216 εμφανίσεις

Frames on the
S
creen

(http://easyjavatutorial.weebly.com/the
-
jframe.html)

One can use
JFrame
to create a window and add components through it's
add
() method.

JFrame window = new JFrame();

window.add(new JLabel("This is a Label"));


You can set the title of the window with it's
setTitle
() method.

window.setTitle("This is a window");


You can set the size of the window with it's
setSize
() method.

window.setSize(640, 480);

You should make the window visible.


window.setVisible(true);


C
reating

a window

This
example creates a window.

import javax.swing.*;

import java.awt.*;


public class ShowWindow {


public static void main(String[] args){


JFrame window = new JFrame("This is a window!");


// You

can also set the title in this way


window.setSize(240, 100);


window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


// Set's the default close operation to EXIT program.


//It's not default


window.setLocationRelativeTo(null);


// Position's the window in the center


window.setVisible(true);


// Show the window


}

}

Output
:



The JLabel

JLabel

is the component which is used to display text on the Frame.


Usage
:

JLabel t1 = new JLabel("Any text here");

// you can also create from String variables


JLabel t2 = new JLabel(message);

// message is a String variable


You can change the text anytime by using it's
setText
() method.

t1.setText("New Text");


You can retrieve the text in String format by using
getText
() method.

String str = t1.getText();


JLabel in a window

import javax.swing.*;

import java.awt.*;


public

class JLabelInFrame extends JFrame {


public JLabelInFrame(){


super("Label in a JFrame");


setSize(240, 100);


setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


add(new JLabel("This is a JLabel"));


setResizable(false);


setLocationRelativeTo(null);


setVisible(true);


}


public static void main(String[] args){


new JLabelInFrame();


}

}

Output
:



JButton

The JButton

is a swing component which is used to create buttons in an application.

You can instantiate it like this.

JButton button = new JButton();

//or//

JButton button = new JButton("Default value");

You can change the text of the JButton with the
setText
()
method

button.setText("New Text");

You can get the text of the JButton with the
getText
() method

String txt = button.getText();

To know whether a button is clicked, we use the ActionListener interface.



Listening to the Components

To listen
to
the components such as to know whether a button is pressed or not..., we have to
import the event package, which is a subclass of java.awt package. First let us import it.

import java.awt.event.*;

To listen the calls we need to implement the
ActionListener

interface

public class MyClass extends JFrame implements ActionListener {


...

}

Set up the ActionListener for the components by the
addActionListener
() method.

new JButton("Test button").addActionListener(this);

// or //

JButton button = new JButto
n("Test Button");

button.addActionListener(this);

You should implement the
actionPerformed
(
ActionEvent
e) method

public void actionPerformed(ActionEvent e){


...

}

If you are using too many buttons, and added actionListener's to them, you would want
to know
which button was actually pressed.

public void actionPerformed(ActionEvent e){


Object src = e.getSource();


if (src==b1){


// button 1 was clicked


} else if (src==b2){


// button 2 was clicked


} else {


// nothing was clicked


}

}


The Layout Managers

In the previous example, the label really looked odd.. To overcome this, we use the Layout
Managers.

The Layout Managers gives us more control on the style of our windows.

There are many built
-
in
Layout Managers in java. If you need more you can create on with WYSIWYG editors.


The different Layout Managers which are common are.....



FlowLayout



GridLayout



BoxLayout

Creating a Layout Manager

Any Layout Manager you use should be declared first.

// The FlowLayout Manager

FlowLayout flo = new FlowLayout();

// The GridLayout Manager

GridLayout grid = new GridLayout(2, 3); // 2 rows and 3 columns

// The BoxLayout Manager

BoxLayout box = new BoxLayout(BoxLayout.Y_AXIS, null);


To use it, we have to use the
setLayout
() method of the container (Frame, JPanel etc..);

window.setLayout(flo);


FlowLayout

when used arranges swing components from left to right until there’s no more space
available. Then it begins a new row below it and moves from left to right again. Each component
in a FlowLayout gets as much space as it needs and no more.

FlowLayout
Examp
le
Source Code

import java.awt.ComponentOrientation;

import java.awt.Container;

import java.awt.Dimension;

import java.awt.FlowLayout;

import javax.swing.JButton;

import javax.swing.JCheckBox;

import javax.swing.JFrame;

import javax.swing.JLabel;

import ja
vax.swing.JTextField;


public class FlowLayoutDemo {


public static boolean RIGHT_TO_LEFT = false;


public static void addComponents(Container contentPane) {


if (RIGHT_TO_LEFT) {


contentPane.setComponentOrientation(


ComponentOrientation.RIGHT_TO_LEFT);


}


contentPane.setLayout(new FlowLayout());


contentPane.add(new JLabel("JLabel 1"));


contentPane.add(new JButton("JButton 2"));


contentPane.add(new JCheckBox("JChec
kBox 3"));


contentPane.add(new JTextField("Long
-
Named JTextField 4"));


contentPane.add(new JButton("JButton 5"));


}



private static void createAndShowGUI() {


JFrame.setDefaultLookAndFeelDecorated(true);


JFrame frame
= new JFrame("FlowLayout Source Demo") {


public Dimension getMinimumSize() {


Dimension prefSize = getPreferredSize();


return new Dimension(100, prefSize.height);


}


};


frame.setDefaultC
loseOperation(JFrame.EXIT_ON_CLOSE);


//Set up the content pane and components in FlowLayout


addComponents(frame.getContentPane());


frame.pack();


frame.setVisible(true);


}



public static void main(String[] args) {


javax.swing.SwingUtilities.invokeLater(new Runnable() {


public void run() {


createAndShowGUI();


}


});


}

}

Output


BorderLayout Manager

BorderLayout

places swing components in the North, South, East, West and center of a
container. All extra space is placed in the center area. You can add horizontal and vertical gaps
between the areas.

Every content pane is initialized to use a BorderLayout. Component
s are added to a
BorderLayout by using the add method. JFrame’s content pane default layout manager:
BorderLayout. In BorderLayout, a component’s position is specified by a second argument to
add.

BorderLayout
Example
Source Code

/*


* BorderLayoutDemo.java requires no other files.


*/

import java.awt.BorderLayout;

import java.awt.Container;

import java.awt.Dimension;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;


public class BorderLayoutDemo {



public static boolean RIGHT_TO_LEFT = false;


public static void addComponentsToPane(Container contentPane) {

//
U
se BorderLayout. Default empty constructor with no horizontal and vertical

//

gaps



contentPane.setLayout(new BorderLayout(5,5));


if (!(contentPane.getLayout() instanceof BorderLayout)) {


contentPane.add(new JLabel("Container doesn't use BorderLayout!"));


return;


}


if (RIGHT_TO_LEFT) {


contentPane.setComponentOrientation(



java.awt.ComponentOrientation.RIGHT_TO_LEFT);


}


JButton jbnSampleButtons = new JButton("Button 1 (PAGE_START)");


contentPane.add(jbnSampleButtons, BorderLayout.PAGE_START);


jbnSampleButtons = new JButton
("Button 2 (CENTER)");


jbnSampleButtons.setPreferredSize(new Dimension(200, 100));


contentPane.add(jbnSampleButtons, BorderLayout.CENTER);



jbnSampleButtons = new JButton("Button 3 (LINE_START)");


contentPane.add(
jbnSampleButtons, BorderLayout.LINE_START);


jbnSampleButtons = new JButton("Long
-
Named Button 4 (PAGE_END)");


contentPane.add(jbnSampleButtons, BorderLayout.PAGE_END);


jbnSampleButtons = new JButton("5 (LINE_END)");


contentP
ane.add(jbnSampleButtons, BorderLayout.LINE_END);


}



private static void createAndShowGUI() {


JFrame.setDefaultLookAndFeelDecorated(true);


JFrame frame = new JFrame("BorderLayout Source Demo");


frame.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);



//Set up the content pane and add swing components to it


addComponentsToPane(frame.getContentPane());


frame.pack();


frame.setVisible(true);


}



public static void main(String[] args) {



javax.swing.SwingUtilities.invokeLater(new Runnable() {


public void run() {


createAndShowGUI();


}


});


}

}

output




GridLayout Manager

GridLayout

is a layout manager that lays out a container’s components in a rectangular grid. The
container is divided into equal
-
sized rectangles, and one component is placed in each rectangle.

GridLayout
Example
Source Code

import java.awt.*;

import javax.swing.*;


public class GridLayoutDemo {


public final static boolean RIGHT_TO_LEFT = false;



public static void addComponentsToPane(Container contentPane) {


if (RIGHT_TO_LEFT) {


contentPane.setComponentOrientation(


Compone
ntOrientation.RIGHT_TO_LEFT);


}

// Any number of rows and 2 columns


contentPane.setLayout(new GridLayout(0,2));



contentPane.add(new JLabel("JLabel 1"));


contentPane.add(new JButton("JButton 2"));


contentPane.
add(new JCheckBox("JCheckBox 3"));


contentPane.add(new JTextField("Long
-
Named JTextField 4"));


contentPane.add(new JButton("JButton 5"));


}



private static void createAndShowGUI() {


JFrame.setDefaultLookAndFeelDecorated(true
);



JFrame frame = new JFrame("GridLayout Source Demo");


frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);



//Set up the content pane and components in GridLayout


addComponentsToPane(frame.getContentPane());



frame.pack();


frame.setVisible(true);


}



public static void main(String[] args) {


javax.swing.SwingUtilities.invokeLater(new Runnable() {


public void run() {


createAndShowGUI();


}


});


}

}

Output




http://easyjavatutorial.weebly.com/the
-
jtextfield.html

The JTextField

The JTextField is a component which represents a Text
-
box which can be added to the JFrame


The location of the JTextField is


import javax.swing.JTextField;



You can construct a JTextField like this

JTextField tf = new JTextField(); // The default constructor

JTextField tf2 = new JTextField(25); // Constructs the
JTextField of size

JTextField tf3 = new JTextField("Hello World", 25); // With size
and default t
ext


You can set the text or retrieve it in the same way as a JLabel


tf.setText("New Text"); /* or */ tf.setText(txt);

String str = tf.getText();


You can add it to the JFrame


frame.add(new JTextField("Hello World", 25));

// or //

frame.add(tf);

JTextField in a JFrame

import javax.swing.*;

import java.awt.*;


public class TFInFrame extends JFrame {


public TFInFrame(){


super("JTextField in a JFrame");


// Use the dafault metal styled titlebar


setUndecorated(true);



getRootPane().setWindowDecorationStyle(JRootPane.FRAME);


// Set the style of the frame


add(new JTextField("I'm a JTextField", 25));


setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


setResizable(false);


setLayout(new
FlowLayout());


pack();


setLocationRelativeTo(null);


setVisible(true);


}


public static void main(String[] args){


new TFInFrame();


}

}


JTextField

allows editing/displaying of a single line of text. New features include the ability to
justify the text left, right, or center, and to set the text’s font. When the user types data into them
and presses the Enter key, an action event occurs. If the progr
am registers an event listener, the
listener processes the event and can use the data in the text field at the time of the event in the
program. JTextField is an input area where the user can type in characters. If you want to let the
user enter multiple l
ines of text, you cannot use Jtextfield’s unless you create several of them.
The solution is to use
JTextArea
, which enables the user to enter multiple lines of text.

JTextField Source Code

// A program to demonstrate the use of JTextFields's

//Import
Statements

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;


public class JTextFieldDemo extends JFrame {



//Class Declarations


JTextField jtfText1, jtfUneditableText;


String disp = "";


TextHandler handler = null;


//Constructor


publi
c JTextFieldDemo() {



super("TextField Test Demo");



Container container = getContentPane();



container.setLayout(new FlowLayout());



jtfText1 = new JTextField(10);



jtfUneditableText = new JTextField("Uneditable text field", 20);



jtfUneditableText.
setEditable(false);



container.add(jtfText1);



container.add(jtfUneditableText);



handler = new TextHandler();



jtfText1.addActionListener(handler);



jtfUneditableText.addActionListener(handler);



setSize(325, 100);



setVisible(true);


}


//Inner Class TextHandler


private class TextHandler implements ActionListener {




public void actionPerformed(ActionEvent e) {




if (e.getSource() == jtfText1) {





disp = "text1 : " + e.getActionCommand();




} else if (e.getSource() == jtfUneditableT
ext) {





disp = "text3 : " + e.getActionCommand();




}




JOptionPane.showMessageDialog(null, disp);



}


}


//Main Program that starts Execution


public static void main(String args[]) {



JTextFieldDemo test = new JTextFieldDemo();



test.setDefaultCl
oseOperation(JFrame.EXIT_ON_CLOSE);


}

}// End of class TextFieldTest

Output



Another Example:

public class JTextFieldDemo2 extends JFrame implements ActionListener {


JTextField jtfInput;


JTextArea jtAreaOutput;


String newline = "
\
n";


public
JTextFieldDemo2() {



createGui();


}


public void createGui() {



jtfInput = new JTextField(20);



jtfInput.addActionListener(this);



jtAreaOutput = new JTextArea(5, 20);



jtAreaOutput.setEditable(false);



JScrollPane scrollPane = new JScrollPane(jtAre
aOutput,





JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,





JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);



GridBagLayout gridBag = new GridBagLayout();



Container contentPane = getContentPane();



contentPane.setLayout(gridBag);



GridBagConstraints gridCons1 =
new GridBagConstraints();



gridCons1.gridwidth = GridBagConstraints.REMAINDER;



gridCons1.fill = GridBagConstraints.HORIZONTAL;



contentPane.add(jtfInput, gridCons1);



GridBagConstraints gridCons2 = new GridBagConstraints();



gridCons2.weightx = 1.0;



gridCons2.weighty = 1.0;



contentPane.add(scrollPane, gridCons2);


}


public void actionPerformed(ActionEvent evt) {



String text = jtfInput.getText();



jtAreaOutput.append(text + newline);



jtfInput.selectAll();


}


public static void main(String[]
args) {



JTextFieldDemo2 jtfTfDemo = new JTextFieldDemo2();



jtfTfDemo.pack();



jtfTfDemo.addWindowListener(new WindowAdapter() {





public void windowClosing(WindowEvent e) {





System.exit(0);




}



});



jtfTfDemo.setVisible(true);


}

}

Output







Listening the Components

To listen the components such as to know whether a button is pressed or not..., we have to import
the event package, which is a subclass of java.awt package. First let us import it.

import java.awt.event.*;

To listen

the calls we need to implement the ActionListener interface


public class MyClass extends JFrame implements ActionListener {


...

}

Set up the ActionListener for the components by the addActionListener() method.


new JButton("Test button").
addActionListener(this);

// or //

JButton button = new JButton("Test Button");

button.addActionListener(this);


You should implement the actionPerformed(ActionEvent e) method

public void actionPerformed(ActionEvent e){


...

}

If you are using too man
y buttons, and added actionListener's to them, you would want to know
which button was actually pressed.

public void actionPerformed(ActionEvent e){


Object src = e.getSource();


if (src==b1){


// button 1 was clicked


} else if (src==b2){


// button 2 was clicked


} else {


// nothing was clicked


}

}




--------------------------------------------------------------------------------------------------------

http://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html

How to Use Text Fields

(Oracle Docs)

A text field is a basic text control that enables the user to type a small amount of text. When the
user indicates that text entry is complete (us
ually by pressing Enter), the text field fires an
action
event
. If you need to obtain more than one line of input from the user, use a
text area
.

The Swing API provides several classes for components that are either varieties of text fields or
that include text fields.

JTextField

What this section covers: basic text fields.

JFormattedTextField

A
JTextField

subclass that allows you to specify the legal set of
characters that the user can enter. See
How to Use Formatted Text
Fields
.

JPasswordField

A
JTextField

subclass that does not show the characters that the
user types. See
How to Use Password Fields
.

JComboBox

Can be edited, and provides a menu of strings to choose from. See
How to Use Combo Boxes
.

JSpinner

Combines a formatted text field with a couple of small buttons that
enables the user to choose the previous or next available value. See
How to Use Spinners
.

The following example displays a basic text field and a text area. The text field is editable. The
text area is not editable. When the user presses Enter in the text field, the program copies the text
fie
ld's contents to the text area, and then selects all the text in the text field.


Click the Launch button to run TextDemo using
Java™ Web Start

(
download JDK 7 or later
).
Alternatively, to compile and run the example yourself, consult the
example index
.


You can find the entire code for this program in
TextDemo.java
. The foll
owing code creates and
sets up the text field:

textField = new JTextField(20);

The integer argument passed to the
JTextField

constructor,
20

in the example, indicates the
number of columns in the field. This number is used along with metrics provided by the field's
current font to calculate the field's preferred width. It does not limit the number of characters the
user can enter. To do that,
you can either use a
formatted text field

or a document listener, as
described in
Text Component Features
.


Note:


We encourage you to specify the number of columns for each text field. If you do not specify the
number of columns or a preferred size, then the field's

preferred size changes whenever the text
changes, which can result in unwanted layout updates.


The next line of code registers a
TextDemo

object as an action listener for the text field.

textField.addActionListener(this);

The
actionPerformed

method hand
les action events from the text field:

private final static String newline = "
\
n";

...

public void actionPerformed(ActionEvent evt) {


String text = textField.getText();


textArea.append(text + newline);


textField.selectAll();

}

Notice the use of

JTextField
's
getText

method to retrieve the text currently contained by the
text field. The text returned by this method does
not

include a newline character for the Enter key
that fired the action event.

You have seen how a basic text field can be used.
Because the
JTextField

class inherits from
the
JTextComponent

class, text fields are very flexible and can be customized almost any way
you like. For example, you can add a document listener or a document filter to be notified when
the text changes, and in

the filter case you can modify the text field accordingly. Information on
text components can be found in
Text Component Features
. Before customizing a
JTextField
,
however, make sure that one of the other
components based on text fields

will not do the job for
you.

Often text fields are paired with labels that desc
ribe the text fields. See
Examples That Use Text
Fields

for pointers on creating these pairs.

Another Example: TextFieldDemo

The
TextFieldDemo

example introduces a text field and a text area. You can find the entire code
for this program in
TextFie
ldDemo.java
.

As you type characters in the text field the program searches for the typed text in the text area. If
the entry is found it gets highlighted. If the program fails to find the entry then the text field's
background becomes pink. A status bar be
low the text area displays a message whether text is
found or not. The Escape key is used to start a new search or to finish the current one. Here is a
picture of the
TextFieldDemo

application.


Click the Launch button ro run TextFieldDemo using
Java™ Web Start

(
download JDK 7 or
later
). Alternatively, to compile and run the exa
mple yourself, consult the
example index
.

To highlight text, this example uses a highlighter and a painter. The code below creates and sets
up
the highlighter and the painter for the text area.

final Highlighter hilit;

final Highlighter.HighlightPainter painter;

...

hilit = new DefaultHighlighter();

painter = new DefaultHighlighter.DefaultHighlightPainter(HILIT_COLOR);

textArea.setHighlighter(hil
it);

This code adds a document listener to the text field's document.

entry.getDocument().addDocumentListener(this);

Document listener's
insertUpdate

and
removeUpdate

methods call the
search

method, which
not only performs a search in the text area but also handles highlighting. The following code
highlights the found text, sets the caret to the end of the found match, sets the default background
for the text field, and displays a message in
the status bar.

hilit.addHighlight(index, end, painter);

textArea.setCaretPosition(end);

entry.setBackground(entryBg);

message("'" + s + "' found. Press ESC to end search");

The status bar is a
JLabel

object. The code below shows how the
message

method is
implemented.

private JLabel status;

...

void message(String msg) {


status.setText(msg);

}

If there is no match in the text area, the following code changes the text field's background to
pink and displays a proper information message.

entry.setBackground(ERROR_COLOR);

message("'" + s + "' not found. Press ESC to start a new search");

The
CancelAction

class is responsible for handling the Escape key as follows.


class CancelAction extends AbstractAction {


public void actionPerfo
rmed(ActionEvent ev) {


hilit.removeAllHighlights();


entry.setText("");


entry.setBackground(entryBg);


}


}

Event
-
driven programming is very different from "traditional" programming, and probably most

prevalent when working with Graphical User Interfaces and Game Programming. In more "traditional,"
we perform tasks like prompting the user for input, evaluating that input and responding to that input in
a loop, with significant control being placed on t
he users' actions. So for example:

1

int[] x = new int[10];

2

Scanner scan = new Scanner(System.in);

3

for(int i = 0; i < x.length; i++){

4


System.out.println("Enter number " + (i+1));


5


x[i] = scan.nextInt();

6

}



Event
-
driven programming
is different, though. Rather than placing so much control on gathering input,
we focus on responding to that input. So basically, when a button is clicked, we write the code to
respond. When a key is pressed, or the mouse moved, etc., we respond to those r
espective events. This
is how GUI programming is, as well as a lot of Game Programming. So if the user doesn't select
something, then our program never responds. This may not be extremely clear right now, but after we
examine the components of an Event
-
Dri
ven model, I think the differences will become more apparent.


In any Event
-
driven model, we have three components: the trigger, the listener, and the response. The
trigger is usually something the users interact with (like a JButton), but not always (in t
he case of Swing
Timer). Basically, it fires an event. This is where the Listener comes in. As a trigger cannot listen for its
own events, we need a separate component to do such. The Listener basically invokes the response.


An analogy for the event
-
driv
en model would be a light switch. We have the trigger (the switch), the
Listener (the wiring), and the response (the light turning on). In addition, it is there for the user to click
at will, but we are not notifying and prompting them to turn on the light
.


A basic example illustrating the event
-
driven model in Java, commented to identify the trigger, listener,
and response.

01
//we have a class which will display a window

02

//and listen for the button clicks

03

public class MyFrame extends JFrame imp
lements ActionListener{

04



05


private JButton button = new JButton();

06


private int count = 0;

07



08


public MyFrame(){

09


this.setSize(200,200);

10


this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

11


this.add(button);

12



13


//we are telling button that it has a listener

14


//for its ActionEvent, marking the JButton as the trigger

15


//and this object as the listener

16


button.addActionListener(this)
;

17


this.add(button);

18


this.setVisible(true);

19


}

20



21


//this is our response

22


//when the listener is notified of an event

23


//being fired, it will invoke this method

24


public void actionPerformed(ActionEvent

e){

25


button.setText("I have been clicked " + (++count) + " times");

26


}

27



28

}



Event D
riven
P
rogramming

Event driven programming is a way of writing a program that works by responding to things
happening (rather than executing a preplanned series of tasks). It is most often used to manage
more advanced user interactions, such as GUI programs. In this session

we look at how event
driven programming works in Java GUIs, as both an introduction to events (using
MouseListeners), and also to the way that GUI programs are constructed.


Introduction to Intera
ctive Programming

by
Lynn Andrea Stein

A
Rethinking CS101

Project

Event
-
Driven Programming


Chapter Overview



How do we design an entity to emphasize its

responses to various events?

In previous chapters, we have seen how an animate object can use its explicit control loop as a
dispatcher, calling appropriate methods depending on what input it receives. In this chapter, we
discuss a style of programming
that shifts the emphasis from the dispatcher to the various
handler methods called by that control loop. Entities designed in this way highlight their
responses to a variety of situations, now called events. An implicit
--

behind
-
the
-
scenes
--

control
loop

dispatches to these event handler methods.

This event
-
driven style of programming is very commonly used in graphical user interfaces
(GUIs). In Java, AWT's paint methods are an example of this kind of event
-
driven programming.
This chapter closes with an
exploration of a portion of the
java.awt

package, including
java.awt.Component and its subclasses, to illustrate the structure of programs written in an event
-
driven style.




Objectives

1.

To recognize event
-
driven control

2.

To understand that event handlers

describe responses to events, not their causes

3.

To be able to write event handlers for simple event
-
driven systems


Control Loops and Handler Methods

W
e will explore how one writes handlers for special circumstances, assuming that these handler
methods
will be called when they are needed. By the end of this chapter, we will turn to a system
in which this is true without programmer effort, i.e., in which Java takes responsibility for
ensuring that the handler methods are called when they are needed.

The b
asic idea of
event
-
driven programming

is simply to create objects with methods that
handle the appropriate events or circumstances, without explicit attention to how or when these
methods will be called. These helper methods provide answers to questions of

the form, "What
should I do when xxx happens?" Because xxx is a "thing that happens", or an
event
, these
methods are sometimes called
event handlers
. As the writer of event handler methods, you
expect that the event handlers will somehow (automatically) b
e invoked whenever the
appropriate thing needs dealing with, i.e., whenever the appropriate event arises.[Footnote:
Ensuring that those event handler methods will be called is a precondition for event
-
driven
programming, not a part of it. We will return to

the question of precisely how this can be
accomplished later in this chapter.]

The result of this transformation is that your code focuses on the occasions when something of
interest happens
--

instead of the times when nothing much is going on
--

and on
how it should
respond to these circumstances. An event is, after all, simply something (significant) that
happens. This style of programming is called event
-
driven because the methods that you write
--

the event handlers
--

are the instructions for how to
respond to events.



http://en.wikibooks.org/wiki/Java_Programming/Event_Handling

The Event Model framework


The
B
asic Event Model
F
ramework

The Event Model framework is really very simple in and of itself, consisting of three classes
(one abstract) and
an interface. Most of all it consists of naming conventions that the
programmer must obey. The framework is depicted in the image on the right.

Speaking in terms of classes and interfaces, the most important parts of the framework are the
java.util.EventOb
ject abstract class and the java.util.EventListener interface. These two types are
the centerpieces of the rules and conventions of the Java Platform Event Model, which are:



A class that has to be notified when an event occurs, is called an
event listener
.

An event
listener has one distinct method for each type of event notification that it is interested in.



Event notification method declarations are grouped together into categories. Each
category is represented by an event listener interface, which must ex
tend
java.util.EventListener. By convention an event listener interface is named
<Event
category name>Listener
. Any class that will be notified of events must implement at
least one listener interface.



Any and all state related to an event occurrence will
be captured in a state object. The
class of this object must be a subclass of java.util.EventObject and must record at least
which object was the source of the event. Such a class is called an event class and by
convention is named
<Event category name>Eve
nt
.



Usually (but not necessarily!) an event listener interface will relate to a single event class.
An event listener may have multiple event notification methods that take the same event
class as an argument.



An event notification method usually (but not
necessarily!) has the conventional
signature
public

void

<specific event>(<Event category name>Event evt)
.



A class that is the source of events must have a method that allows for the registration of
listeners, one for each possible listener interface type. These methods must by conve
ntion
have the signature
public

void

add<Event category name>Listener(<Event category
name>Listener listener)
.



A class that is the source of events may have a method that allows for the deregistration

of listeners, one for each possible listener interface type. These methods must by
convention have the signature
public

void

remove<Event category
name>Listener(<Event category name>Listener listener)
.



A general example of how the framework is used

That seems like a lot, but it'
s pretty simple once you get used to it. Take a look at the image on
the left, which contains a general example of how you might use the framework. In this example
we have a class called EventSourceClass that publishes interesting events. Following the rul
es of
the Event Model, the events are represented by the InterestingEvent class which has a reference
back to the EventSourceClass object (source, inherited from java.util.EventObject).

Whenever an interesting event occurs, the EventSourceClass must notify

all of the listeners for
that event that it knows about by calling the notification method that exist for that purpose. All of
the notification methods (in this example there is only one, interestingEventOccurred) have been
grouped together by topic in a
listener interface: InterestingEventListener, which implements
java.util.EventListener and is named according to the Event Model conventions. This interface
must be implemented by all event listener classes (in this case only
InterestingEventListenerImpl).

Because EventSourceClass must be able to notify any interested
listeners, it must be possible to register them. For this purpose the EventSourceClass has an
addInterestingEventListener method. And since it is required, there is a
removeInterestingEventLis
tener method as well.

As you can clearly see from the example, using the Event Model is mostly about following
naming conventions. This might seem a little cumbersome at first, but the point of having
naming conventions is to allow automated tooling to acc
ess and use the event model. And there
are indeed many tools, IDEs and frameworks that are based on these naming conventions.

Degrees of freedom in the Model

There's one more thing to notice about the Event Model and that is what is
not

in the Model. The
Event Model is designed to allow implementations a large degree of freedom in the
implementation choices made, which means that the Event Model can serve as the basis for a
very wide range of specific, purpose
-
built event handling system
s.

Aside from naming conventions and some base classes and interfaces, the Event Model specifies
the following:



It must be possible to register and deregister listeners.



An event source must publish events by calling the correct notification method on all
registered listeners.



A call to an event notification method is a normal, synchronous Java call and the method
must be executed by the same thread that called it.

But the Event Model doesn't specify
how

any of this must be done. There are no rules regardin
g
which classes exactly must be event sources, nor about how they must keep track of registered
event listeners. So one class might publish its own events, or be responsible for publishing the
events that relate to an entire collection of objects (like an
entire component). And an event
source might allow listeners to be deregistered at any time (even in the middle of handling an
event) or might limit this to certain times (which is relevant to multithreading).

Also, the Event Model doesn't specify how it m
ust be embedded within any program. So, while
the model specifies that a call to an event handling method is a synchronous call, the Model does
not prescribe that the event handling method cannot hand off tasks to another thread or that the
entire event mo
del implementation must run in the main thread of the application. In fact, the
Java Platform's standard user interface framework (
Swing
) includes an event hand
ling
implementation that runs as a complete subsystem of a desktop application, in its own thread.

Event notification methods, unicast event handling and event adaptors

In the previous section we mentioned that an event notification method usually takes a
single
argument. This is the preferred convention, but the specification does allow for exceptions to this
rule if the application really needs that exception. A typical case for an exception is when the
event notification must be sent across the network t
o a remote system though non
-
Java means,
like the
CORBA

standard. In this case it is required to have multiple arguments and the Event
Model allows for that. However, as a general
rule the correct format for a notification method is


Code section 1.1: Simple notification method


public void specificEventDescription(Event_type evt)

Another thing we mentioned earlier is that, as a general rule, the Event Model allows many event
listeners to register with a single event source for the same event. In this case the event source
must broadcast any relevant events to all the registered lis
teners. However, once again the Event
Model specification allows for an exception to the rule. If it is necessary from a design point of
view you may limit an event source to registering a single listener; this is called
unicast event
listener registration
. When unicast registration is used, the registration method must be declared
to throw the java.util.TooManyListenersException exception if too many listeners are registered:


Code section 1.2: Listener registration


public void add<Event_type>Listener(<E
vent_type>Listener listener)
throws java.util.TooManyListenersException



An event adaptor in between the event source and the event listener.

Finally, the specification allows for one more extension: the event adaptor. An event adaptor is
an
implementation of an event listener interface that can be inserted between an event source and
an actual event listener class. This is done by registering the adaptor with the event source object
using the regular registration method. Adaptors are used to
add additional functionality to the
event handling mechanism, such as routing of event objects, event filtering or enriching of the
event object before processing by an actual event handler class.

A simple example

In the previous section we've explored the

depths (such as there are) of the Java platform Event
Model framework. If you're like most people, you've found the theoretical text more confusing
than the actual use of the model. Certainly more confusing than should be necessary to explain
what is, rea
lly, quite a simple framework.

In order to clear everything up a bit, let's examine a simple example based on the Event Model
framework. Let's assume that we want to write a program that reads a stream of numbers input
by the user at the command line and p
rocesses this stream somehow. Say, by keeping track of the
running sum of numbers and producing that sum once the stream has been completely read.

Of course we could implement this program quite simply with a loop in a main() method. But
instead let's be a

little more creative. Let's say that we want to divide our program neatly into
classes, each with a responsibility of its own (like we should in a proper, object
-
oriented design).
And let's imagine that we want it to be possible not only to calculate the
sum of all the numbers
read, but to perform any number of calculations on the same number stream. In fact, it should be
possible to add new calculations with relative ease and without having to affect any previously
existing code.

If we analyze these requi
rements, we come to the conclusion that we have a number of different
responsibilities in the program:



Reading the number stream from the command line



Processing the number stream (possibly multiple of these)



Starting the entire program

Using the Event Mo
del framework allows us to separate the two main responsibilities cleanly
and affords us the flexibility we are looking for. If we implement the logic for reading the
number stream in a single class and treat the reading of a single number as an event, the

Event
Model allows us to broadcast that event (and the number) to as many stream processors as we
like. The class for reading the number stream will act as the event source of the program and
each stream processor will be a listener. Since each listener i
s a class of its own and can be
registered with the stream reader (or not) this means our model allows us to have multiple,
independent stream processing that we can add on to without affecting the code to read the
stream or any pre
-
existing stream process
or.

The Event Model says that any state associated with an event should be included in a class that
represents the event. That's perfect for us; we can implement a simple event class that will record
the number read from the command line. Each listener can

then process this number as it sees fit.

For our interesting event set let's keep things simple: let's limit ourselves to having read a new
number and having reached the end of the stream. With this choice we come to the following
design for our example a
pplication:



In the following sections we look at the implementation of this example.

Example basics

Let's start with the basics. According to the Event Model rules, we must define an event class to
encapsulate our interesting event. We should call this

class
something
-
something
Event. Let's go
for NumberReadEvent, since that's what will interest us. According to the Model rules, this class
should encapsulate any state that belongs with an event occurrence. In our case, that's the number
read from the str
eam. And our event class must inherit from java.util.EventObject. So all in all,
the following class is all we need:


Code listing 1.1: NumberReadEvent.


package org.wikibooks.en.javaprogramming.example;



import java.util.EventObject;



public class
NumberReadEvent extends EventObject {




private Double number;




public NumberReadEvent(Object source, Double number) {


super(source);


this.number = number;


}




public Double getNumber() {


return number;


}

}

Next, we must define a listener interface. This interface must define methods for interesting
events and must extend java.util.EventListener. We said earlier our interesting events were
"number read" and "end of stream reached", so here we go:


Code listi
ng 1.2: NumberReadListener.


package org.wikibooks.en.javaprogramming.example;



import java.util.EventListener;



public interface NumberReadListener extends EventListener {


public void numberRead(NumberReadEvent numberReadEvent);




public void nu
mberStreamTerminated(NumberReadEvent
numberReadEvent);

}

Actually the numberStreamTerminated

method is a little weird, since it isn't actually a "number
read" event. In a real program you'd probably want to do this differently. But let's keep things
simple in this example.

The event listener implementation

So, with our listener interface defined,

we need one or more implementations (actual listener
classes). At the very least we need one that will keep a running sum of the numbers read. We can
add as many as we like, of course. But let's stick with just one for now. Obviously, this class
must impl
ement our NumberReadListener interface. Keeping a running summation is a matter of
adding numbers to a field as the events arrive. And we wanted to report on the sum when the end
of the stream is reached; since we know when that happens (i.e. the numberStr
eamTerminated
method is called), a simple println statement will do:


Code listing 1.3: NumberReadListenerImpl.




package org.wikibooks.en.javaprogramming.example;

public class NumberReadListenerImpl implements NumberReadListener {


Double totalSoFar

= 0D;


@Override


public void numberRead(NumberReadEvent numberReadEvent) {


totalSoFar += numberReadEvent.getNumber();


}


@Override


public void numberStreamTerminated(NumberReadEvent numberReadEvent) {


System.out.println("
Sum of the number stream: " + totalSoFar);


}

}


So, is this code any good? No. It's yucky and terrible and most of all not thread safe. But it will
do for our example.

The event source

This is where things get interesting: the event source class. This is the interesting place because
this is where we must put code to read the number stream, code to send events to all the listeners
and code to
manage

listeners (add and remove them and kee
p track of them).

Let's start by thinking about keeping track of listeners. Normally this is a tricky business, since
you have to take all sorts of multithreading concerns into account. But we're being simple in this
example, so let's just stick with a sim
ple java.util.Set of listeners. Which we can initialize in the
constructor:


Code section 1.1: The constructor




private Set<NumberReadListener> listeners;

public NumberReader() {


listeners = new HashSet<NumberReadListener>();

}


That choice makes
it really easy to implement adding and removing of listeners:


Code section 1.2: The register/deregister





public void addNumberReadListener(NumberReadListener listener) {


this.listeners.add(listener);

}

public void removeNumberReadListener(
NumberReadListener listener) {


this.listeners.remove(listener);

}

We won't actually use the remove method in this example


but recall that the Model says it
must be present.

Another advantage of this simple choice is that notification of all the liste
ners is easy as well. We
can just assume any listeners will be in the set and iterate over them. And since the notification
methods are synchronous (rule of the model) we can just call them directly:


Code section 1.3: The notifiers




private void
notifyListenersOfEndOfStream() {


for (NumberReadListener numberReadListener : listeners) {


numberReadListener.numberStreamTerminated(new NumberReadEvent(this, 0D));


}

}



private void notifyListeners(Double d) {


for (NumberReadListener
numberReadListener: listeners) {


numberReadListener.numberRead(new NumberReadEvent(this, d));


}

}


Note that we've made some assumptions here. For starters, we've assumed that we'll get the
Double value d from somewhere. Also, we've assumed tha
t no listener will ever care about the
number value in the end
-
of
-
stream notification and have passed in the fixed value 0 for that
event.

Finally we must deal with reading the number stream. We'll use the Console class for that and
just keep on reading nu
mbers until there are no more:


Code section 1.4: The main method




public void start() {


Console console = System.console();


if (console != null) {


Double d = null;


do {


String readLine = console.readLine("Enter a
number: ", (Object[])null);


d = getDoubleValue(readLine);


if (d != null) {


notifyListeners(d);


}


} while (d != null);


notifyListenersOfEndOfStream();


}

}

Note how we've hooked the
number
-
reading loop into the event handling mechanism by calling
the notify methods? The entire class looks like this:


Code listing 1.4: NumberReader.




package org.wikibooks.en.javaprogramming.example;



import java.io.Console;

import java.util.HashSe
t;

import java.util.Set;



public class NumberReader {


private Set<NumberReadListener> listeners;




public NumberReader() {


listeners = new HashSet<NumberReadListener>();


}




public void addNumberReadListener(NumberReadListener

listener) {


this.listeners.add(listener);


}




public void removeNumberReadListener(NumberReadListener listener) {


this.listeners.remove(listener);


}




public void start() {


Console console = System.console();



if (console != null) {


Double d = null;


do {


String readLine = console.readLine("Enter a number: ",
(Object[])null);


d = getDoubleValue(readLine);


if (d != null) {



notifyListeners(d);


}


} while (d != null);


notifyListenersOfEndOfStream();


}


}




private void notifyListenersOfEndOfStream() {


for (NumberReadListener numberReadListener: listeners) {



numberReadListener.numberStreamTerminated(new
NumberReadEvent(this, 0D));


}


}




private void notifyListeners(Double d) {


for (NumberReadListener numberReadListener: listeners) {


numberReadListener.numberRead(new
NumberReadEvent(this, d));


}


}




private Double getDoubleValue(String readLine) {


Double result;


try {


result = Double.valueOf(readLine);


} catch (Exception e) {


result = null;


}


return result;


}

}

Running the example

Finally, we need one more class: the kickoff point for the application. This class will contain a
main() method, plus code to create a NumberReader, a listener and to combine the two:


Code listing 1.5: M
ain.


package org.wikibooks.en.javaprogramming.example;



public class Main {




public static void main(String[] args) {


NumberReader reader = new NumberReader();


NumberReadListener listener = new NumberReadListenerImpl();


reader.addNumberReadListener(listener);


reader.start();


}

}

If you compile and run the program, the result looks somewhat like this:


An example run


>java org.wikibooks.en.javaprogramming.example.Main

Enter a number: 0.1

Enter a number: 0.2

Enter a number: 0.3

Enter a number: 0.4

Enter a number:



Output


Sum of the number stream: 1.0


Extending the example with an adaptor

Next, let's take a look at applying an adaptor to our design. Adaptors are used to add
functionality to the event
handling process that:



is general to the process and not specific to any one listener; or



is not supposed to affect the implementation of specific listeners.

According to the Event Model specification a typical use case for an adaptor is to add routing
log
ic for events. But you can also add filtering or logging. In our case, let's do that: add logging
of the numbers as "proof" for the calculations done in the listeners.

An adaptor, as explained earlier, is a class that sits between the event source and the
listeners.
From the point of view of the event source, it masquerades as a listener (so it must implement the
listener interface). From the point of view of the listeners it pretends to be the event source (so it
should have add and remove methods). In oth
er words, to write an adaptor you have to repeat
some code from the event source (to manage listeners) and you have to re
-
implement the event
notification methods to do some extra stuff and then pass the event on to the actual listeners.

In our case we nee
d an adaptor that writes the numbers to a log file. Keeping it simple once
again, let's settle for an adaptor that:



Uses a fixed log file name and overwrites that log file with every program run.



Opens a FileWriter in the constructor and just keeps it open
.



Implements the numberRead method by writing the number to the FileWriter.



Implements the numberStreamTerminated method by closing the FileWriter.

Also, we can make life easy on ourselves by just copying all the code we need to manage
listeners over from
the NumberReader class. Again, in a real program you'd want to do this
differently. Note that each notification method implementation also passes the event on to all the
real listeners:


Code listing 1.6: NumberReaderLoggingAdaptor.


package
org.wikibooks.en.javaprogramming.example;



import java.io.BufferedWriter;

import java.io.FileWriter;

import java.io.IOException;

import java.util.HashSet;

import java.util.Set;



public class NumberReaderLoggingAdaptor implements NumberReadListener {


private Set<NumberReadListener> listeners;


private BufferedWriter output;




public NumberReaderLoggingAdaptor() {


listeners = new HashSet<NumberReadListener>();


try {


output = new BufferedWriter(new FileWriter("numberLog
.log"));


} catch (IOException e) {


// TODO Auto
-
generated catch block


e.printStackTrace();


}


}




public void addNumberReadListener(NumberReadListener listener) {


this.listeners.add(listener);


}




public void removeNumberReadListener(NumberReadListener listener) {


this.listeners.remove(listener);


}






@Override


public void numberRead(NumberReadEvent numberReadEvent) {


try {


output.write(
numberReadEvent.getNumber() + "
\
n");


} catch (Exception e) {




}


for (NumberReadListener numberReadListener: listeners) {


numberReadListener.numberRead(numberReadEvent);


}


}




@Override


public void nu
mberStreamTerminated(NumberReadEvent numberReadEvent) {


try {


output.flush();


output.close();


} catch (Exception e) {




}


for (NumberReadListener numberReadListener: listeners) {


numberRea
dListener.numberStreamTerminated(numberReadEvent);


}


}



}

Of course, to make the adaptor work we have to make some changes to the bootstrap code:


Code listing 1.7: Main.


package org.wikibooks.en.javaprogramming.example;



public class Main

{




public static void main(String[] args) {


NumberReader reader = new NumberReader();


NumberReadListener listener = new NumberReadListenerImpl();


NumberReaderLoggingAdaptor adaptor = new NumberReaderLoggingAdaptor();


a
daptor.addNumberReadListener(listener);


reader.addNumberReadListener(adaptor);


reader.start();


}

}

But note how nicely and easily we can re
-
link the objects in our system. The fact that adaptors
and listeners both implement the
listener interface and the adaptor and event source both look
like event sources means that we can hook the adaptor into the system without having to change
a single statement in the classes that we developed earlier.

And of course, if we run the same exam
ple as given above, the numbers are now recorded in a
log file.