JDK 1.1 was released on February 18, 1997 and JDK 1.1.1 was released on March 27, 1997. This lesson was originally written on March 30, 1997 using the software and documentation in the JDK 1.1.1 download package.
One of my teaching objectives is to present every concept in the simplest possible terms, devoid of confusing extraneous material. This lesson contains about the simplest example program that I was able to write that illustrates the posting of events.
In this lesson, a Label object impersonates a Button object by posting counterfeit ActionEvent objects attributable to the Button. The events are picked up by the system and processed just as though they were actually generated by the Button. In particular, they are delivered to an ActionListener object registered on the Button object where they are processed just as though they originated at the Button object.
This sample program operates completely within the Source/Listener concept of the Delegation Event Model.
Unlike a previous sample program, this program does not override any of the processXxxxEvent() methods. Rather, this program works completely within the Source/Listener concept of the Delegation Event Model.
Two Label objects and a Button object are instantiated and added to a Frame object. When the Button object is clicked, an ActionEvent is generated and trapped by an ActionListener object registered on the Button object. Code in the actionPerformed() method of the ActionListener object toggles the background color of one of the Label objects back and forth between yellow and blue.
Up to this point, everything is pretty normal. However, a MouseListener object is registered on the other Label. When that Label object is clicked, code in the mouseClicked() method of the MouseListener object generates a counterfeit ActionEvent object and posts it to the SystemEventQueue.
The code in the Label's MouseListener object impersonates the Button object by placing the identification of the Button object into the "source" field of the counterfeit ActionEvent object.
The runtime system delivers the counterfeit ActionEvent object to the ActionListener object registered on the Button object. The final result is that clicking on the Label object invokes the actionPerformed() method registered on the Button object, so clicking on the Label object has exactly the same result as clicking on the Button object.
The program was tested using JDK 1.1.1 and Win95. An interesting sidelight is that the counterfeit button constructed from the Label object is much more responsive than the real button. In other words, the counterfeit button can service mouse clicks at a much more rapid rate than the real button.
This probably has something to do with the requirement to redraw the button twice each time it is clicked in order to animate it. An interesting exercise for the student would be to respond to the pressed and released events of the mouse on the Label to change the background color of the Label while it is pressed to see if that would produce a similar degradation of the responsiveness of the counterfeit button.
The first interesting code fragment is the pair of statements in the constructor which register Listener objects on the Label and the Button. An important point to note is that a reference to the Button object is passed to the constructor of the MouseListener object for the Label. It is through this link that the Label is able to create a counterfeit ActionEvent object and attribute it to the Button.
It is also interesting to note that the Listener object for the
Label knows nothing about the other Label object whose color
is changed during the operation of the program. This is because the Label
object that impersonates the Button does not directly change
the color of the other Label object. Rather, by impersonating the
Button object, it causes the ActionListener object on the
Button to perform that task. In fact, it has no knowledge of the
outcome of its impersonation. All it knows is that it posts an ActionEvent
object and attributes it to the Button.
clickMeLabel.addMouseListener( new MyMouseListener(clickMeButton)); clickMeButton.addActionListener( new MyActionListener(colorMeLabel)); |
In this case, that reference is passed as a parameter when the MouseListener object is constructed but there are probably other ways to accomplish this as well. For example, code might be able to "peek" into the SystemEventQueue in hopes of copying an ActionEvent object and obtaining a reference to the Button. That is why special security provisions apply to the SystemEventQueue for Applets.
Because the counterfeit ActionEvent object is attributed
to the Button object, it is delivered to the ActionListener object
for the Button where it is processed just as though it actually
originated at the Button.
//Note that the following is a single statement Toolkit.getDefaultToolkit(). getSystemEventQueue(). postEvent(new ActionEvent(clickMeButton, ActionEvent. ACTION_PERFORMED, "counterfeit")); |
public ActionEvent(Object source, int id, String command)
specified source object. originated command - the command string for this action event |
As mentioned in an earlier lesson, it is very important that you specify a correct id parameter. Otherwise, the ActionEvent object won't be delivered by the runtime system.
I promised you earlier that this was going to be a simple program. The remaining code is standard code that you have seen many times before so we won't highlight it as being interesting. A complete listing of the program is presented in the next section.
/*File Event31.java Copyright 1997, R.G.Baldwin
Reformatted 10/5/97 to fit better on the screen.
This program was designed to be compiled and executed under
JDK 1.1.1.
This program demonstrates the use of the postEvent() method
to post ActionEvents to the SystemEventQueue. In this
program, a Label object impersonates a Button object by
posting counterfeit ActionEvent objects and attributes them
to the Button object.
Unlike a previous sample program, this program does not
override any of the processXxxxEvent() methods. Rather,
this program works completely within the Source/Listener
concept of the Delegation Event Model.
Two Labels and a Button are instantiated and added to a
Frame object. When the Button object is clicked, an
ActionEvent is generated and trapped by an ActionListener
object registered on the Button object. Code in the
actionPerformed() method of the Listener object toggles
the background color of one of the Label objects back and
forth between yellow and blue.
So far, everything is pretty standard. However, a
MouseListener object is registered on the other Label.
When that Label object is clicked, code in the
mouseClicked() method of the MouseListener object generates
a synthetic or counterfeit ActionEvent object and posts it
to the SystemEventQueue.
The code in the Label's MouseListener object impersonates
the Button object by placing the identification of the
Button object into the "source" field of the counterfeit
ActionEvent object.
The runtime system delivers the counterfeit ActionEvent
object to the ActionListener object registered on the
Button object. The final result is that clicking on the
Label object invokes the actionPerformed() method
registered on the Button object, so clicking on the Label
object has exactly the same result as clicking on the
Button object.
The program was tested using JDK 1.1.1 (and later
JDK 1.1.3) and Win95. An interesting sidelight is that the
counterfeit button constructed from the Label object is
more responsive than the real button. In other words, the
counterfeit button can service mouse clicks at a more rapid
rate than the real button.
*/
import java.awt.*;
import java.awt.event.*;
//=========================================================
public class Event31 extends Frame{
public static void main(String[] args){
Event31 displayWindow = new Event31();//instantiate obj
}//end main
//-------------------------------------------------------
public Event31(){//constructor
setTitle("Copyright 1997, R.G.Baldwin");
setLayout(new FlowLayout());
Button clickMeButton = new Button("Click Me");
Label colorMeLabel = new Label("Color Me");
Label clickMeLabel = new Label("Click Me");
add(clickMeButton);//add components to the Frame object
add(colorMeLabel);
add(clickMeLabel);
setSize(250,100);//set frame size
setVisible(true);//display the frame
//Register listener objects
clickMeLabel.addMouseListener(
new MyMouseListener(clickMeButton));
clickMeButton.addActionListener(
new MyActionListener(colorMeLabel));
//terminate when Frame is closed
this.addWindowListener(new Terminate());
}//end constructor
}//end class Event31
//=========================================================
/*This MouseListener class is used to monitor for mouse
clicks on a Label object. Whenever the user clicks on the
label, the code in an object of this class creates a
counterfeit ActionEvent object and posts it to the
SystemEventQueue. The source of the event is specified to
be a particular Button object that is passed in when an
object of this class is instantiated. Thus, the Label
object "claims" to be the Button object and posts
ActionEvent objects that are interpreted by the runtime
system as originating at the Button object. The type of
ActionEvents generated are ACTION_PERFORMED events. The
events are automatically delivered to the actionPerformed()
method of an ActionListener object registered on the
button. */
class MyMouseListener extends MouseAdapter{
Button clickMeButton;//reference to the Button
//-------------------------------------------------------
MyMouseListener(Button inButton){//constructor
clickMeButton = inButton;//save reference to Button
}//end constructor
//-------------------------------------------------------
//overridden mouseClicked() method
public void mouseClicked(MouseEvent e){
//Note that the following is a single statement
Toolkit.getDefaultToolkit().
getSystemEventQueue().
postEvent(new ActionEvent(clickMeButton,
ActionEvent.
ACTION_PERFORMED,
"counterfeit"));
}//end overridden mouseClicked() method
}//end MyMouseListener
//=========================================================
/*This ActionListener class is used to instantiate a
Listener object for the Button object. Whenever the button
is clicked, or a counterfeit ActionEvent is posted with the
Button as the specified source object, the code in an
object of this class toggles the background color of a
Label object back and forth between yellow and blue.*/
class MyActionListener implements ActionListener{
int toggle = 0;
Label myLabel;
//-------------------------------------------------------
MyActionListener(Label inLabel){//constructor
myLabel = inLabel;
}//end constructor
//-------------------------------------------------------
public void actionPerformed(ActionEvent e){
if(toggle == 0){
toggle = 1;
myLabel.setBackground(Color.yellow);
}else{
toggle = 0;
myLabel.setBackground(Color.blue);
}//end else
}//end actionPerformed()
}//end class myActionListener
//=========================================================
class Terminate extends WindowAdapter{
public void windowClosing(WindowEvent e){
//terminate the program when the window is closed
System.exit(0);
}//end windowClosing
}//end class Terminate
//========================================================= |
A - See the specifications and the
solution below.
/*File SampProg133.java Copyright 1997, R.G.Baldwin
Without viewing the solution that follows, write a Java
application that replicates the behavior of the application
named Event31.java (discussed in lesson 106) with the
following changes.
This is an upgrade to the original version of Event31.
In particular, in its original form, there is no visual
indication when the user clicks on the Label object
identified by the Click Me caption. Since this Label object
is being used to simulate a Button object, a visual
indication that the Label object has been clicked would be
appropriate.
In your upgraded version, the white Label object which
originally had the Click Me caption will appear as a
magenta colored rectangle when the program starts and will
not display a caption.
When the user clicks the magenta Label object, the caption
"ouch" will momentarily appear and disappear in synchronism
with the down stroke and the up stroke of the left mouse
button. The caption will appear on the down stroke and
will disappear on the upstroke.
In addition to the above, make your name appear in the
banner at the top of the Frame object.
The upgraded version of the program has been tested using
JDK 1.1.3 under Win95.
*/
//=========================================================
import java.awt.*;
import java.awt.event.*;
//=========================================================
public class SampProg133 extends Frame{
public static void main(String[] args){
//instantiate obj
SampProg133 displayWindow = new SampProg133();
}//end main
//-------------------------------------------------------
public SampProg133(){//constructor
setTitle("Copyright 1997, R.G.Baldwin");
setLayout(new FlowLayout());
Button clickMeButton = new Button("Click Me");
Label colorMeLabel = new Label("Color Me");
Label clickMeLabel = new Label(" ");
clickMeLabel.setBackground(Color.magenta);
add(clickMeButton);//add components to the Frame object
add(colorMeLabel);
add(clickMeLabel);
setSize(300,100);//set frame size
setVisible(true);//display the frame
//Register listener objects
clickMeLabel.addMouseListener(
new MyMouseListener(clickMeButton,clickMeLabel));
clickMeButton.addActionListener(
new MyActionListener(colorMeLabel));
//terminate when Frame is closed
this.addWindowListener(new Terminate());
}//end constructor
}//end class SampProg133
//=========================================================
/*This MouseListener class is used to monitor for mouse
clicks on a Label object. Whenever the user clicks on the
label, the code in an object of this class creates a
counterfeit ActionEvent object and posts it to the
SystemEventQueue. The source of the event is specified to
be a particular Button object that is passed in when an
object of this class is instantiated. Thus, the Label
object "claims" to be the Button object and posts
ActionEvent objects that are interpreted by the runtime
system as originating at the Button object. The type of
ActionEvents generated are ACTION_PERFORMED events. The
events are automatically delivered to the actionPerformed()
method of an ActionListener object registered on the
button. */
class MyMouseListener extends MouseAdapter{
Button clickMeButton;//reference to the Button
Label clickMeLabel;//reference to the Label
//-------------------------------------------------------
//constructor
MyMouseListener(Button inButton,Label inLabel){
clickMeButton = inButton;//save reference to Button
clickMeLabel = inLabel;//save reference to Label
}//end constructor
//-------------------------------------------------------
//overridden mouseClicked() method
public void mouseClicked(MouseEvent e){
//Note that the following is a single statement
Toolkit.getDefaultToolkit().
getSystemEventQueue().
postEvent(new ActionEvent(clickMeButton,
ActionEvent.
ACTION_PERFORMED,
"counterfeit"));
}//end overridden mouseClicked() method
//------------------------------------------------------
//overridden mousePressed() method
public void mousePressed(MouseEvent e){
clickMeLabel.setText(" ouch ");
}//end overridden mousePressed() method
//------------------------------------------------------
//overridden mouseReleased() method
public void mouseReleased(MouseEvent e){
clickMeLabel.setText(" ");
}//end overridden mousePressed() method
}//end MyMouseListener
//=========================================================
/*This ActionListener class is used to instantiate a
Listener object for the Button object. Whenever the button
is clicked, or a counterfeit ActionEvent is posted with the
Button as the specified source object, the code in an
object of this class toggles the background color of a
Label object back and forth between yellow and blue.*/
class MyActionListener implements ActionListener{
int toggle = 0;
Label myLabel;
//-------------------------------------------------------
MyActionListener(Label inLabel){//constructor
myLabel = inLabel;
}//end constructor
//-------------------------------------------------------
public void actionPerformed(ActionEvent e){
if(toggle == 0){
toggle = 1;
myLabel.setBackground(Color.yellow);
}else{
toggle = 0;
myLabel.setBackground(Color.blue);
}//end else
}//end actionPerformed()
}//end class myActionListener
//=========================================================
class Terminate extends WindowAdapter{
public void windowClosing(WindowEvent e){
//terminate the program when the window is closed
System.exit(0);
}//end windowClosing
}//end class Terminate
//========================================================= |