Before starting on today's lab, finish up Lab 14 from Monday.
The goal of this lab is to design windows requesting
input from the user.
You can unpack the files you'll be working with by cloning the
repository for lab15
:
hg clone /cslab/class/csci235/labs/lab15 cd lab15
In the last lab, your work was mostly with the class
JButton
and interface ActionListener
, with a
little bit of work to create a frame and lay out the buttons in it.
This lab expands the set of components in your toolbox. We will talk
about the additional components in class, but you can try them out
now.
Change (cd
) into the samples
directory
within the lab. This has an example program from class that uses several
instances of JTextField
, which displays as a box in which
the user can type. As with JLabel
, you can call its
methods getText()
and setText()
.
You can
also use addActionListener()
: unless you do something
fancy, the listener's actionPerformed()
will be called
when the user hits the ENTER key while typing in the box. If you
uncomment the line for field.addActionListener
, it will
install the same listener that is also listening for a click on the button.
Note that the value in JTextField
must be a string.
To convert an input to a numeric value, you will need to use the
parsing method from class Integer
or
Double
. Those methods throw a
NumberFormatException
if the string is not parsable.
Once you are comfortable with this example, move on to the real
work, which is in the sprites
subdirectory.
Today we go back to a simulation of the same sort as the predator-prey example and the ball-catching project. We will have a grid inhabited by agents, each acting in its own way.
The grid we'll be working with today will be inhabited by Sprites. A Sprite is an object that moves about the grid in a way determined by the following parameters:
Then compile and run the program Sprites
.
Notice that there is a jar
file;
you'll need to refer to it on the command line when you
compile and run.
javac -cp simulation.jar:. Sprites.java java -cp simulation.jar:. Sprites
By default there is a single Sprite.
If you inspect the code in Sprites.java
,
you'll see that the Sprite is created by a call to addSprite()
addSprite(100, 100, .25 * Math.PI, .125 * Math.PI, 3, Color.RED, model));That in turn instantiates the new Sprite and installs it in the grid (
model
).
Inspect the file Sprite.java
to understand what these
parameters for the constructor mean.
The intent of this program is to allow the user to add new Sprites to the system as the simulation runs. Pressing the button Add Sprite should launch a dialog window asking the user for all the specifications of the Sprite and add that Sprite to the grid. However, when you press the button, nothing happens. That's for you to write.
("Dialog" is not meant to be a Java-specific technical term; it just means a smallish window on the screen temporarily to get input from the user.)
Read the entire lab description before you start writing any code. It will help you to see the program as a whole, and there are also some hints lurking toward the end.
AddListener
classThe Add Sprite button has an action listener attached to it.
However, the actionPerformed()
method is
just a skeleton.
Your main task is to fill in this method, which
will prompt the user with a dialog box.
As you add things to the window in your program,
It is a good idea to periodically compile and
run this class to see how the window looks so far,
and then make some adjustments.
Make the window look reasonably nice; play with
the dimensions and the layout until it looks right.
To make just looking at window easier, the class
AddListener
contains a simple main()
method
that simply shows the window.
Here are things that ought to be in the dialog box:
JColorChooser
.
This displays a color palette which the user
may click on to select a color.
Then the program can read that color from
the JColorChooser
object.
See the Java API documentation to find out more about this
class.
You will almost certainly want to use the no-parameter constructor
and the method getColor()
.
Since it will be hard to indicate a value including π when entering a direction or rotational velocity, you should interpret the user's input in these fields as a coefficient of π. In other words, if the user enters ".5" into the direction field, you should interpret that to mean ".5π". Also, all these text fields should have an accompanying appropriate label.
The actionPerformed()
method does two things: it
stops the simulation, and it makes the dialog window visible.
Whichever button gets pressed, the handler calls the AddListener
's
reset()
to hide the dialog and resume the simulation.
Note that the comments suggest setting the dialog's default to
DO_NOTHING_ON_CLOSE
. That forces the user to use the
Cancel button to close the dialog, so that the simulation will
get resumed. A listener for the Cancel button has been provided for you.
The actionPerformed()
method should also
make the dialog box appear. You will need to write the action
listener for the Ok button, as discussed below. I have
provided a listener for the Cancel button; it simply calls back
to the AddListener
's reset()
method.
and it should attach
another action listener to the Ok button, but
that action listener will be the subject of the next
part.
The provided code suggests that you have the constructor for
AddListener
do the work of setting up an invisible
window, with the associated action listener for its Ok button.
With that arrangement, this first actionPerformed()
is quite simple.
Write another class, also implementing ActionListener
,
that will react to the Ok button being pressed.
Specifically, the actionPerformed()
method
should
reset()
) on the AddListener
to hide
the dialog and resume the simulator.
First, you should think about what pieces of information
this action listener needs to know (hint: a lot).
These will become instance variables
and parameters to the constructor.
Then writing the actionPerformed()
method will be easier.
Note that you need need to get the text from the textfields after the user hits Ok.
The JColorChooser
is bigger than you might guess; it
is something like 420x220 pixels. You
probably want to your other components into a single
panel with its own layout, and put that and the color chooser into
your window with either a flow layout or the default border layout.
An awkward thing about building a dialog this way is that it is
hard to know in advance how big the components in your window should
be. But if you choose your layout classes appropriately, you can do a
first version without worrying about getting the window size exactly
right. You can run that program using the main method in
AddListener
, then resize the window to make it look
good. Once you have that, you can use the command
xwininfo
to find out the size. Run the command in a
terminal window, then click on the window you want to find out about.
It is often helpful if you can get the easier parts of a program working first, then add features bit by bit. So you might think about the simplest working version of your dialog: with just the Cancel button working. Then you could get the minimal listener set up for Ok, without worrying about reading the fields or adding the sprite. You could then turn your attention to reading and parsing the fields, but then just print the values instead of creating the sprite. By adding just a little bit at a time, then testing it, you have a better idea where to look when something doesn't work correctly.
If the user does not put a valid number into one of the text
fields, your program will spew largely unintelligible complaints in
the terminal window. You can improve on that by putting the calls to
parse the numbers inside of a try
block. But what should
you do when you catch one of those exceptions?
The simpler (but less polished) option is to print an
intelligible message in the terminal window, and keep the
dialog visible to let the user fix the mistakes (or hit cancel).
One way to make the operations a bit more polished would be to
add another label to the dialog window, and use setText()
on it to show a message to user. You'll just need to be careful that
you clear that message at the right time, too.
As time permits, improve the way you program handles bad input.
From the sprites
subdirectory, turn in the source files you created or modified with a command such as
/cslab/class/csci235/bin/handin lab15 *.java
Be sure to include all of your files on a single command.