Event-Driven Programming
1. Event-Driven Programming
Reading: Liang Sect 16.1
1.1 Conventional Programming vs Event-Driven Programming
All the programs you have studied or you wrote are executed in order. There is an entry point (the main method in a class) and an exit (the program finishes the task and exit the main method). The program simply terminates after the assigned jobs are done.
However if you look at an event-driven program, for example, MS Word. After you launch the word program, you can do your jobs, and the program never exit until you close the window/click “Exit” menu from the “File” menus. In this way you (as a user) create an event (Exit event or a “message”) which means you want to shut down the program. When the program gets the event (message), the program exits. Of course you always create many other kinds of events by clicking menus on the menu bar, clicking buttons on the tool bar, typing text into your files etc. Almost everything you do creates an event to the program and then the program processes the event and gets your requests done.
1.2 A simple example
Study the programs in Listings 16.1 and 16.2 carefully and run them. Record anything you don’t understand and keep it in mind.
When the second program is run, you can press the Enlarge button and see an effect in the console window. Every time you press the button, the button fires an ActionEvent. The program has installed/associated an ActionListener to listen to the ActionEvent to be created by the button, thus the listener will get the message (‘the button is pressed’) when the button is pressed by a user. Once the listener gets the message, the task(s) defined in the actionPerformed method will be performed. Here the task is to enlarge the circle.
The process is: A component (e.g. button) triggers an event (ActionEvent), then the pre-installed listener gets the event (ActionEvent) and invokes its action performer (actionPerformed method). The job to be done should be defined in the action performer.
2. Event, event source and user action
2.1 Events
Java defines many event classes. ActionEvent is just one of them. EventObject is the superclass of others. Figure 16.2 of the text book lists all of them. We will learn more about ActionEvent, FocusEvent, MouseEvent and WindowEvent etc.
2.2 Event sources
An event source is an object (a GUI component) on which an event may be triggered. For example, in Listing 16.2 the event source is the Enlarge button because it triggers an ActionEvent. An event source will be associated with (called registeration) one or more event listener to listen to possible events to be triggered on the event source.
2.3 User actions
When you run Java GUI programs, the program interacts with the user. A user takes actions on the components on the user interface, for example, press a button, click on a menu etc. The actions are operated on components. Then the components as event source trigger events which are captured by event listeners.
Table 16.1 lists the relationships of user actions, source objects and event types. It is important for you to understand which source object can trigger which events.
2.4 Listeners
For every event type there is a listener interface. For example corresponding to the like ActionEvent we have the ActionListenerinterface which has an actionPerformed method. You need to implement the ActionListener interface by defining this method, i.e., putting in what you want to do with this action.
The listener interface is usually named Xlistener for Xevent: For example, ActionLister for ActionEvent; WindowListenerfor WindowEvent etc.
3. Another example
This example will demonstrate the ActionEvent again that you have seen in Listing 16.2 of the text book. The program creates a user interface with three buttons, each of which will change the background of the window to color of Red, Blue or Green.
3.1 Creating the User Interface (the Window)
import javax.swing.*;
import java.awt.*;
import java.awt.*;
public class TestActionEvent {
public static void main( String[] argv ) {
JFrame myframe = new ButtonFrame();
myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myframe.setVisible(true);
}
}
public static void main( String[] argv ) {
JFrame myframe = new ButtonFrame();
myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myframe.setVisible(true);
}
}
class ButtonFrame extends JFrame
{
public ButtonFrame(){
ButtonPanel p = new ButtonPanel();
add(p);
setTitle("Color Buttons");
setSize(400, 400);
setLocationRelativeTo(null);
}
}
{
public ButtonFrame(){
ButtonPanel p = new ButtonPanel();
add(p);
setTitle("Color Buttons");
setSize(400, 400);
setLocationRelativeTo(null);
}
}
class ButtonPanel extends JPanel
{
public ButtonPanel()
{
JButton redButton = new JButton("Red");
JButton greenButton = new JButton("Green");
JButton blueButton = new JButton("Blue");
add(redButton);
add(greenButton);
add(blueButton);
}
}We create a JPanel with three buttons first, then add the panel to the frame with size (400, 400). Running this program you will see three buttons at the top row of the frame/window. Of course the buttons are dummy: no response when you click on them.
{
public ButtonPanel()
{
JButton redButton = new JButton("Red");
JButton greenButton = new JButton("Green");
JButton blueButton = new JButton("Blue");
add(redButton);
add(greenButton);
add(blueButton);
}
}We create a JPanel with three buttons first, then add the panel to the frame with size (400, 400). Running this program you will see three buttons at the top row of the frame/window. Of course the buttons are dummy: no response when you click on them.
3.2 Extending Listeners for Button ActionEvents
To make buttons change the background color of the window, we need to create listeners for the buttons. As the buttons triggerActionEvent, we should extend the ActionListener interface.
class redAction implements ActionListener
{
public void actionPerformed(ActionEvent event){
setBackground(Color.RED);
}
}
{
public void actionPerformed(ActionEvent event){
setBackground(Color.RED);
}
}
class greenAction implements ActionListener
{
public void actionPerformed(ActionEvent event){
setBackground(Color.GREEN);
}
}
{
public void actionPerformed(ActionEvent event){
setBackground(Color.GREEN);
}
}
class blueAction implements ActionListener
{
public void actionPerformed(ActionEvent event){
setBackground(Color.BLUE);
}
}
{
public void actionPerformed(ActionEvent event){
setBackground(Color.BLUE);
}
}
3.3 Registering Listeners with Buttons
To make each listener work with its button, you need to register it with the button. Insert the following into ButtonPanel’s constructor
redAction redAct = new redAction(); //creating listener instance
greenAction greenAct = new greenAction();
blueAction blueAct = new blueAction();
greenAction greenAct = new greenAction();
blueAction blueAct = new blueAction();
redButton.addActionListener(redAct); //register listener with button
greenButton.addActionListener(greenAct);
blueButton.addActionListener(blueAct);
greenButton.addActionListener(greenAct);
blueButton.addActionListener(blueAct);
3.4 Using Inner Class Listeners
If you simply put the above code together, you will find it does not work. I suggest you should try it first to see what will happen there.
The problem is with the setBackground method. The compiler do not know what it is. Actually we want to call Panel’s setBackgroundmethod. For us to use the panel’s setBackground method, you could put the implementation classes redAction, greenAction andblueAction insider the panel class. They are called inner classes.
Generally speaking, if an event listener is going to access another component, you need to implement the listener as an inner class of the component.
Then we have solved the problem. The full version of the code is displayed below. Please try it.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.*;
import java.awt.event.*;
public class TestActionEvent {
public static void main( String[] argv ) {
JFrame myframe = new ButtonFrame();
myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myframe.setVisible(true);
}
}
public static void main( String[] argv ) {
JFrame myframe = new ButtonFrame();
myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myframe.setVisible(true);
}
}
class ButtonFrame extends JFrame
{
public ButtonFrame(){
ButtonPanel p = new ButtonPanel();
add(p);
setTitle("Color Buttons");
setSize(400, 400);
setLocationRelativeTo(null);
}
}
{
public ButtonFrame(){
ButtonPanel p = new ButtonPanel();
add(p);
setTitle("Color Buttons");
setSize(400, 400);
setLocationRelativeTo(null);
}
}
class ButtonPanel extends JPanel
{
public ButtonPanel()
{
JButton redButton = new JButton("Red");
JButton greenButton = new JButton("Green");
JButton blueButton = new JButton("Blue");
add(redButton);
add(greenButton);
add(blueButton);
redAction redAct = new redAction(); //creating
greenAction greenAct = new greenAction();
blueAction blueAct = new blueAction();
{
public ButtonPanel()
{
JButton redButton = new JButton("Red");
JButton greenButton = new JButton("Green");
JButton blueButton = new JButton("Blue");
add(redButton);
add(greenButton);
add(blueButton);
redAction redAct = new redAction(); //creating
greenAction greenAct = new greenAction();
blueAction blueAct = new blueAction();
redButton.addActionListener(redAct);
greenButton.addActionListener(greenAct);
blueButton.addActionListener(blueAct);
}
class redAction implements ActionListener
{
public void actionPerformed(ActionEvent event){
setBackground(Color.RED);
}
}
class greenAction implements ActionListener
{
public void actionPerformed(ActionEvent event){
setBackground(Color.GREEN);
}
}
greenButton.addActionListener(greenAct);
blueButton.addActionListener(blueAct);
}
class redAction implements ActionListener
{
public void actionPerformed(ActionEvent event){
setBackground(Color.RED);
}
}
class greenAction implements ActionListener
{
public void actionPerformed(ActionEvent event){
setBackground(Color.GREEN);
}
}
class blueAction implements ActionListener
{
public void actionPerformed(ActionEvent event){
setBackground(Color.BLUE);
}
}
}
{
public void actionPerformed(ActionEvent event){
setBackground(Color.BLUE);
}
}
}
3.4 Making code simpler
If you carefully study the code in the above program, you may see a lot of repeating code. For example, why do we need three implementation classes for the ActionLister? Can we simply implement the ActionLister interface in only one class, and create three objects for three colors?
Instead of defining three classes, we use the following class with a constructor which accept a color parameter. The color value provided by the constructor will be stored in a private variable backgroundColor. Try the simplified version below
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.*;
import java.awt.event.*;
public class TestActionEvent {
public static void main( String[] argv ) {
JFrame myframe = new ButtonFrame();
myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myframe.setVisible(true);
}
}
public static void main( String[] argv ) {
JFrame myframe = new ButtonFrame();
myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myframe.setVisible(true);
}
}
class ButtonFrame extends JFrame
{
public ButtonFrame(){
ButtonPanel p = new ButtonPanel();
add(p);
setTitle("Color Buttons");
setSize(400, 400);
setLocationRelativeTo(null);
}
}
{
public ButtonFrame(){
ButtonPanel p = new ButtonPanel();
add(p);
setTitle("Color Buttons");
setSize(400, 400);
setLocationRelativeTo(null);
}
}
class ButtonPanel extends JPanel {
public ButtonPanel() {
JButton redButton = new JButton("Red");
JButton greenButton = new JButton("Green");
JButton blueButton = new JButton("Blue");
add(redButton);
add(greenButton);
add(blueButton);
ColorAction redAct = new ColorAction(Color.RED);
ColorAction greenAct = new ColorAction(Color.GREEN);
ColorAction blueAct = new ColorAction(Color.BLUE);
public ButtonPanel() {
JButton redButton = new JButton("Red");
JButton greenButton = new JButton("Green");
JButton blueButton = new JButton("Blue");
add(redButton);
add(greenButton);
add(blueButton);
ColorAction redAct = new ColorAction(Color.RED);
ColorAction greenAct = new ColorAction(Color.GREEN);
ColorAction blueAct = new ColorAction(Color.BLUE);
redButton.addActionListener(redAct);
greenButton.addActionListener(greenAct);
blueButton.addActionListener(blueAct);
}
class ColorAction implements ActionListener {
public ColorAction(Color c) {
backgroundColor = c;
}
public void actionPerformed(ActionEvent event) {
setBackground(backgroundColor);
}
private Color backgroundColor;
}
}
greenButton.addActionListener(greenAct);
blueButton.addActionListener(blueAct);
}
class ColorAction implements ActionListener {
public ColorAction(Color c) {
backgroundColor = c;
}
public void actionPerformed(ActionEvent event) {
setBackground(backgroundColor);
}
private Color backgroundColor;
}
}
4. Handling with Window Events
[No longer part of ITC313/521]
5. Handling with mouse events
Mouse actions imposed by the user are very complicated. For example, a user may move the mouse when holding the left button of the mouse, move the wheel on a mouse, click on the left button, the right button and both buttons at the same time, and more complicatedly hold a mouse button when press a key on the keyboard etc. Even a simple click action on mouse button may trigger three mouse events: mouse button pressed, mouse button released and mouse clicked.
5.1 Mouse events
Java defines MouseEvent class. You can use methods defined in the class to get information about the MouseEvent object. For example, you can get the coordinate of the mouse pointer by its getX() and getY() methods. Also you can recognize which mouse button is clicked by the user with the getButton() method.
Please have a look at Figure 16.11 for more methods and try to understand the program in Listing 16.9.
5.2 Mouse event listeners
Usually a component is the event source when the mouse actions by the user takes place on the component. Java provides two listener interfaces: MouseListener and MouseMotionListener to handle mouse events.
public interface MouseListener {
void mouseClicked(MouseEvent event); //invoked when mouse button has
been clicked (ie. Pressed and released)
void mouseEntered(MouseEvent event); //invoked when mouse enters the
component
void mouseExited(MouseEvent event); //invoked when mouse exits the
component
void mousePressed(MouseEvent event); //invoked when mouse pressed on
the component
void mouseReleased(MouseEvent event); //invoked when mouse released
on the component
}
void mouseClicked(MouseEvent event); //invoked when mouse button has
been clicked (ie. Pressed and released)
void mouseEntered(MouseEvent event); //invoked when mouse enters the
component
void mouseExited(MouseEvent event); //invoked when mouse exits the
component
void mousePressed(MouseEvent event); //invoked when mouse pressed on
the component
void mouseReleased(MouseEvent event); //invoked when mouse released
on the component
}
and
public interface MouseMotionListener {
void mouseDragged(MouseEvent event); // Invoked when a mouse pressed
on a component and then dragged.
void mouseMoved(MouseEvent event); //Invoked when the mouse cursor
//has been moved onto a component but no
//buttons have been pushed.
}
void mouseDragged(MouseEvent event); // Invoked when a mouse pressed
on a component and then dragged.
void mouseMoved(MouseEvent event); //Invoked when the mouse cursor
//has been moved onto a component but no
//buttons have been pushed.
}
Like the WindowListener interface, if you don’t want to implement all the methods, you can simply use the adapters: MouseAdapterand MouseMotionAdapter.
No comments:
Post a Comment