Java Programming Notes # 1476
Preface
Programming in Java doesn’t have to be dull and boring. In fact,
it’s possible to have a lot of fun while programming in Java. This
is the third lesson in a short miniseries that shows you how to use the
Robot class to write programs that are both fun and useful.
New features in SDK Version 1.3
One of the new features that was released in SDK Version 1.3 was the Robot
class. According to Sun,
“This class is used to generate native system input events for the
purposes of test automation, self-running demos, and other applications
where control of the mouse and keyboard is needed. The primary purpose of
Robot is to facilitate automated testing of Java platform implementations.”
What is a Java robot?
The Robot class makes it possible for your Java program to temporarily
take control of the mouse and keyboard input functionality at the operating-system
level.
Several instance methods are available
The Robot class provides several instance methods, (including
the following), by which your program can produce mouse and keyboard
input, just as though that input were being provided by a human user.
- mouseMove – Moves the mouse pointer to a set of specified absolute
screen coordinates given in pixels. - mousePress – Presses one of the buttons on the mouse.
- mouseRelease – Releases one of the buttons on the mouse.
- keyPress – Presses a specified key on the keyboard.
- keyRelease – Releases specified key on the keyboard.
A word of caution
A runaway Java Robot object has the ability to wrest control away
from the human user, so you need to be a little careful. For example,
if you allow your Java Robot program to go into an infinite loop,
making mouse moves, clicking the mouse, and entering keystrokes, you may
find that the only practical way to regain control of your computer is to
either turn off the power or press the reset button to force your computer
to restart.
Three lessons in the miniseries
According to my current plans, this miniseries on the Robot class
will consist of three lessons. The first lesson, entitled Introduction
to the Java Robot Class in Java, demonstrated the low-level nature
of an object of the Robot class. That was accomplished by
showing you how to create a Java robot that can manipulate other non-Java
programs, such as Windows Notepad and Internet Explorer.
The second lesson, entitled An Automated
Test Program using the Java Robot Class, showed you how to use a robot
to perform automatic testing on a Java GUI.
This lesson will show you how to write a robot program to provide a visual
animated demonstration of the use of a Java GUI.
Viewing tip
You may find it useful to open another copy of this lesson in a separate
browser window. That will make it easier for you to scroll back and
forth among the different listings and figures while you are reading about
them.
Supplementary material
I recommend that you also study the other lessons in my extensive collection
of online Java tutorials. You will find those lessons published at Gamelan.com. However,
as of the date of this writing, Gamelan doesn’t maintain a consolidated index
of my Java tutorial lessons, and sometimes they are difficult to locate there.
You will find a consolidated index at www.DickBaldwin.com.
Preview
A machine with no purpose
Many years ago when I was in engineering undergraduate school, the college
set aside one day each year to invite parents to the college. On that
day, there were numerous programs, including demonstrations of interesting
electrical and mechanical gadgets.
One of the gadgets that I remember was a small wooden box with an electrical
toggle switch on the top. When a person toggled the switch to the
ON position, a small hand emerged from a trap door and toggled the switch
back to the OFF position. Then the hand retreated back into the trap
door and disappeared. The machine had no purpose other than to keep
itself turned off.
An interesting idea
As I was trying to come up with an interesting idea for this lesson,
it occurred to me that a computer simulation of that box might be interesting.
I will discuss a sample program named Robot03 in this lesson.
The sample program will show you how to write a robot program to provide
a visual animated demonstration of the use of a Java GUI.
In this demonstration, the user can use the mouse to toggle any one of
three toggle buttons from not selected to selected.
As in the box described above, as soon as this happens, an animated hand
will move to the button and toggle it back to not selected.
Then the hand will disappear.
Discussion
and Sample Code
Description of the program named Robot03
This program illustrates the use of the Robot class to automatically
unselect a JToggleButton, which has been manually selected by the
user.
This program provides an example of how to create and use a software
robot in an animated fashion. Such animation could be useful in demonstrating
how to use a program with a GUI.
A frame with three toggle buttons
The program places a JFrame object, containing three JToggleButton
objects, near the upper-left corner of the screen. Figure 1 shows
the GUI produced by the program on startup.
Figure 1 Program GUI on startup
As you can see, none of the toggle buttons are selected at startup.
(The buttons initially appear to protrude from the screen in the
Motif look and feel.)
Unfortunately, there is no practical way for me to show you the animation
in this lesson. You will need to compile and execute the program in
order to view the animation in progress.
Will fire action events and toggle between
two states
When the user manually clicks any of the three buttons, or presses the
space bar while one of the buttons has the focus, the button becomes selected
and fires an ActionEvent.
Because the button is a JToggleButton, it will toggle between
being selected and not being selected. When the button is not selected,
it is colored a light shade of gray, and appears to protrude from the screen.
When the button is selected, it is colored a dark shade of gray and appears
to be pushed into the screen.
Focus traversal
If you successively press the focus traversal key, the focus will
traverse the components using the focus traversal policy that is
in effect.
I did not implement a new focus traversal policy, nor did I change the
focus traversal key. Therefore, the default focus traversal policy
and the default focus traversal key are both in effect.
Successively pressing the TAB key will cause the focus to move from one
component to the next, from left to right, and then back to the left end.
If you hold down the SHIFT key and successively press the TAB key, the
focus will traverse the components in the reverse direction.
As mentioned earlier, pressing the space bar while a button has the focus
will cause it to fire an ActionEvent and to toggle between being
selected and not being selected.
Common event handler
A common ActionEvent handler is registered on each of the buttons.
The ActionEvent handler uses an object of the Robot class to
unselect the button in an animated fashion.
The robot takes control of the mouse
As soon as the action event is fired, the robot takes control of the
mouse pointer. The mouse pointer changes from the default arrow-shaped
pointer into a hand-shaped pointer. The hand-shaped pointer becomes
animated, moving from the upper-left area of the GUI to the center of the
button that fired the action event.
The robot clicks the button
When the mouse pointer reaches the center of the button that fired the
event, the robot automatically clicks the button with the mouse, causing
the button to become unselected. This causes the button to once again
appear to protrude from the screen. It also causes the button to change
from dark gray to light gray.
Action events are disabled
Action events are disabled on the button after the user clicks the button
and before the robot clicks the button. Action events are re-enabled
after the robot clicks the button. Otherwise, the program would go
into an infinite loop of firing and processing action events on the same
button.
Robot relinquishes control of the mouse
When the button is clicked by the robot, the robot relinquishes control
of the mouse. The pointer returns to the upper-left area of the GUI
and turns back into the arrow-shaped default pointer. The user can
then click the same, or a different button, starting the animation process
all over again.
Requires V1.3 or later
Because the Robot class was released in SDK Version 1.3, this
program requires V1.3 or later to compile and execute successfully.
The program was tested on my machine using SDK 1.4.1 under WinXP
The beginning of the Robot03 class
I will discuss this program in fragments. A complete listing of
the program is shown in Listing 19 near the end of the lesson.
The program named Robot03 begins in Listing 1 where an instance
variable of type Robot is declared. This variable will later
be used to hold a reference to an object of the Robot class.
public class Robot03 extends JFrame |
Listing 1 also shows the main method, which instantiates an object
of the Robot03 class.
The animated behavior of this program is primarily controlled by the
ActionEvent handler registered on the buttons and by methods called by
the event handler.
The constructor
The constructor begins in Listing 2. The code in the constructor
is relatively straightforward, so I won’t discuss that code in detail.
However, I will review the constructor code briefly to set the stage for
the discussion of the event handler that follows.
public Robot03(){//constructor |
The code in Listing 2 instantiates a new Robot object and saves
its reference in the variable named robot, which was declared in
Listing 1. Because the reference is stored in an instance variable,
it is accessible throughout the class.
Prepare the JFrame for use
The code in Listing 3 executes several routine actions to prepare the
JFrame object for use.
setDefaultCloseOperation( |
Create the buttons …
The code in Listing 4 creates the three JToggleButton objects and
adds them to the frame.
JToggleButton b1 = new JToggleButton( "1" ); |
Register action listeners
The code in Listing 5 registers this object as an action listener
on each of the buttons.
b1.addActionListener(this); |
Set the look and feel
The code in Listing 6 sets the look and feel to Sun’s Motif and makes
the GUI visible.
String plafClassName = |
Listing 6 also signals the end of the constructor.
Now for something a little more interesting
Now that we have gotten beyond the preliminaries, the code should become
a little more interesting, and I will discuss the remaining code in more
detail.
Define the ActionEvent handler
Because the class implements the ActionListener interface, the
class must define the method named actionPerformed, which is declared
in that interface. The definition of the actionPerformed method
is shown in Listing 7.
public void actionPerformed(ActionEvent e){ |
Causing the class to implement the interface and defining the event handler
method within the class makes it possible to register this object
as an ActionEvent handler on each of the buttons as shown earlier
in Listing 5.
The time required to handle the event
One of the important considerations in writing event handlers has to do
with the amount of time that will be required to handle the event in its
entirety. If the amount of time required to handle the event will
be large, the event handler method should spawn a new thread to do the job
and return immediately. This avoids tying the event handler thread
up for long periods while previous events are being handled.
Spawn a thread
Because of the animated nature of this event handler, quite a lot of time
will be required to handle each event fired by a button. The mouse
pointer must move across the GUI at a relatively slow speed in order to
get to and click on the button that fired the event.
Therefore, the actionPerformed method in Listing 7 spawns a new
thread from the inner class named HandleEvent to perform the animation.
The actionPerformed method starts the new thread running and returns
immediately.
The HandleEvent class
The HandleEvent class begins in Listing 8. Objects of this
class, which extends Thread, are spawned to handle the animation
associated with action events on the buttons.
class HandleEvent extends Thread{ |
The constructor
The constructor for the HandleEvent class is shown in Listing 7.
This constructor receives and saves references to:
- The button that fired the event.
- The ActionEvent listener that is registered on the button.
Click on the button
The reference to the button is needed to cause the mouse pointer to move
to the button and click on that button in an animated fashion.
Temporarily disable the action listener
The reference to the listener is needed to temporarily disable the listener
before the robot clicks on the button. Otherwise, the program would
go into an infinite loop with the robot causing the button to fire action
events while trying to handle those events.
The run method
The run method of a Thread object is where the behavior
of that thread is controlled. The beginning of the run method
for the HandleEvent class is shown in Listing 9.
public void run(){ |
The first task in the run method is to get the screen location
of the button that fired the event. This information will be needed
in order to cause the mouse pointer to move to that location and execute
a mouse click.
Disable action events
As mentioned earlier, when the robot causes a mouse click to occur on
the button that fired the event, that button will fire another action
event. If the action listener is still registered on that button,
this will result in an infinite loop of firing and handling action events.
The code in Listing 10 temporarily un-registers the action listener from
the button to prevent this from happening.
button.removeActionListener(listener); |
(The registration of the action listener on the button will be restored
later.)
Move the mouse and click the button
The code in Listing 11 invokes the method named mouseMoveAndClick
to cause to program to:
- Change the mouse pointer to a hand-shaped pointer in the upper left
of the GUI. - Move the pointer slowly from the upper left to the center of the button
that fired the event. - Click the button that fired the event.
- Restore the mouse pointer to the default pointer in the upper left
of the GUI.
This action causes the selected button to become not selected, causing
it to pop out of the screen and to change color from dark gray to light
gray.
mouseMoveAndClick(50,50, |
The mouseMoveAndClick method
At this point, I am going to temporarily put the discussion of the run
method on the back burner and discuss the method named mouseMoveAndClick,
which begins in Listing 12.
public void mouseMoveAndClick(int xStart, |
Move pointer to the starting position
Note that the invocation of this method in Listing 11 passes the coordinates
50, 50 as the first two parameters. This represents a point in the
upper left of the GUI.
The code in Listing 12 moves the mouse pointer to this location in one
step. There is no slow-speed animation associated with this move.
Change to a hand-shaped curser and delay
The code in Listing 13 changes the appearance of the mouse pointer from
its default arrow shape to the shape of a hand. Then a one-second
delay is inserted before the animation actually begins.
setCursor(new Cursor(Cursor.HAND_CURSOR)); |
Compute the incremental mouse pointer step size
A while loop will be used to cause the pointer to move in small
steps from its current location to the center of the button that fired
the event. The code in Listing 14 is used to compute the size of
the steps in the horizontal and vertical directions.
double div; |
Double precision arithmetic
This is the sort of computation where errors associated with integer arithmetic
can accumulate to produce large resulting errors. Therefore, the computations
were performed using double precision to avoid this potential problem.
Different incremental step sizes
If you examine Listing 14 carefully, you will see that the incremental
step size used for the animation depends on how far the mouse needs to travel
to reach the button. This causes the animation to be more visually
pleasing than was the case when I simply used the same step size regardless
of distance. (I will leave it as an exercise for the student to
ponder and understand why this is the case.)
Move the mouse pointer
The code in Listing 15 initializes two variables, and then executes a
while loop to move the mouse pointer in incremental steps from
its starting position in the upper left of the GUI to the center of the
button that fired the event.
double x = xStart; |
A 60-millisecond delay is inserted between each movement of the mouse
pointer to enhance the animation effect.
Click the button
Once the mouse pointer arrives at the center of the button that fired
the event, the while loop terminates and the code in Listing 16
is executed.
robot.mousePress(InputEvent.BUTTON1_MASK); |
The code in Listing 16 first presses and then releases the left mouse
button on the screen location that is the center of the button that fired
the event. This constitutes a click and causes the button to fire
an ActionEvent and to toggle from selected to not selected.
(Because the event listener is no longer registered on the button,
the event is simply ignored. However, the button appears to pop out
of the screen and to change color from dark gray to light gray when it becomes
not selected.)
Finally, the code in Listing 16 inserts a one-second delay to allow the
user to savor the previous action before restoring the pointer to the default
arrow shape in the upper left of the GUI.
Restore the mouse pointer
The code in Listing 17 moves the mouse pointer back to its original
starting position in one step, and changes its appearance from the shape
of a hand to the default shape of an arrow.
robot.mouseMove(xStart,yStart); |
That ends one animation cycle. The mouse pointer is now available
for the user to click on another button and start a new animation cycle.
Re-enable the action listener
Returning now to the remaining code in the run method, the code
in Listing 18 re-registers the action listener object on the button.
button.addActionListener(listener); |
Thus, that button’s ability to fire action events and have them handled
by the action listener is restored.
That ends the class named HandleEvent, and ends the program as
well.
Run the Program
I encourage you to copy the code from Listing 19 into your text editor,
compile it, and execute it. Experiment with it, making changes, and
observing the results of your changes.
The Robot class was first released in SDK Version 1.3, so you
will need to be running Version 1.3 or later to successfully compile and
execute the program. This program was tested on my machine using SDK
1.4.1 under WinXP
Summary
In this lesson, I have taught you how to write an animated robot program
to provide a visual demonstration of the use of a Java GUI.
Complete Program Listings
A complete listing for the program discussed in this lesson is shown in
Listing 19 below.
/*File Robot03.java |
Copyright 2003, Richard G. Baldwin. Reproduction in whole or in part
in any form or medium without express written permission from Richard Baldwin
is prohibited.
About the author
Richard Baldwin is
a college professor (at Austin Community College in Austin, TX) and private
consultant whose primary focus is a combination of Java, C#, and XML. In
addition to the many platform and/or language independent benefits of Java
and C# applications, he believes that a combination of Java, C#, and XML
will become the primary driving force in the delivery of structured information
on the Web.
Richard has participated in numerous consulting projects, and he frequently
provides onsite training at the high-tech companies located in and around
Austin, Texas. He is the author of Baldwin’s Programming Tutorials, which has gained a worldwide
following among experienced and aspiring programmers. He has also published
articles in JavaPro magazine.
Richard holds an MSEE degree from Southern Methodist University and
has many years of experience in the application of computer technology to
real-world problems.
-end-