Graphic by Keith Ohlfs |
|
In this problem, the goal is to build GUI controls for the Fish from Problem 2. You will create a control for each of the Fish's instance methods. For example, you will make a button called "Set Body Color" and a pull-down menu (a Choice menu) to select a color, which will change the Fish's body color to whatever color you have selected. At the end you will have a control panel to the left of the area where the fish will be.
First things first! Download the ps9b_programs folder from the
CS111 download directory. In this folder you will find two files:
FishWorld.java
and FishWorld.html
. Move the
two files (not the whole folder!) into your ps9_programs folder
from Problem 2. Then, in Symantec Cafe, open up your Fish.proj file
(as you should always have your project window open when coding!). Go
to the Project menu, and select Add Files. This will give you a popup
dialogue box. Select the file FishWorld.java
and Add it
to your project. You have now incorporated the new files into your
project.
Start filling the the first set of methods, and then bring the project up to date. The project will not compile successfully until you have filled in these methods.
Because we want to have more than just the Fishtank in our applet
window, the Fish will be drawn in an area of the applet window set
apart by a Canvas. Canvas, like Applet, is a pre-defined class in
Java which you can extend as you like. We will call our Canvas
fishtank
. In Problem 2, the only thing in our applet
window was the fishtank, so we just drew things to the applet window.
In Problem 3, we draw to the Canvas in order to keep the Fish in a
certain area of the applet window, so that you will be able to add the
control panel on the side.
Our overall applet window layout uses a BorderLayout, with the
control panel in the West and the Canvas in the Center. The
init()
method sets up this layout for you.
makeControlPanel()
creates the control panel as described
below, and makeFishtank()
creates the Canvas where the
Fish will be drawn..
The start()
method starts up the applet. In it, we
want to create a new Fish using a method called makeFish
and set the FishWorld instance variable currentFish
to be
this new Fish. You should hand makeFish
the Graphics
context of your Canvas so that it can create the Fish and give it the
correct Graphics context.
Before even worrying about getting things to be clickable in your control panel, just get the control panel to look right. This involves creating the appropriate Panels, Buttons, TextFields, and Choice menus. Remember to specify your Layout for each Panel, and then to put things into it in the right order.
This is done by calling a series of make
methods to
create each Button or TextField, or whatever, to look the way you want
them to look.
The overall control panel uses a grid layout, with a row for each button, and all of them in a single column. You'll notice that some of the rows have multiple items in them (a button and a textfield, for instance). Basically, any time you want more than one thing in a specific part of your grid, you need to create a panel to arrange them together first. So for that button and textfield example, you would need to create a panel which has a button and a textfield in it, and then put the panel into your overall grid layout.
For example, if you wanted a single button in the first part of your grid, you would do something like:
myControls.add (makeMyButton());
in your method that builds your control panel. This adds your
button to the control panel called MyControls by calling the method
makeMyButton
to create the button.
The method makeMyButton()
then creates the button,
puts the labelling text (the words which appear in the button) into
it, and returns the completed button. In fact, the method which makes
the control panel is itself one of these make
methods: it
returns the completed control panel to the init()
method
in your FishWorld class.
You should create your control panel for your FishWorld applet to look like the one shown above. Your Choice menus contain all the color choices for the body and tail of the Fish. You may include any of the usual colors that you want. The TextFields are all length 5.
Once you get things to look right, then you can begin to add functionality to each of your buttons. Your buttons should react as follows:
Button | Action |
Set Body Color | calls Fish method setBodyColor using the current
selectedBodyColor instance variable |
Set Tail Color | calls Fish method setTailColor using the current
selectedTailColor instance variable |
Set Position | reads in the numbers entered in the two TextFields to create a new Point, and then uses the Fish method setPosition to put the Fish at the new Point |
Resize | reads in the number entered in the TextField and hands it to the Fish method resize as the new Fish length |
Swim Up and Down | reads in the number entered in the TextField and hands it to the Fish method swim as the amplitude of swim |
Reset | paints over the Canvas with a white Rectangle and then
calls the start() method to restore the
default Fish |
Start by writing your action
method. The action
method takes two parameters: an Event and an Object. It looks
something like this:
public boolean action (Event event, Object arg) { }
In this method, each possible location for the event (a mouse click, in the cases with which we are concerned) is listed as a conditional, and the appropriate responding action is called. We need to define our conditionals to check if the event's target location was over each GUI element. For instance:
if (event.target == myButton) { //do the right thing } else if (event.target == myNextButton) { //do the right thing }
and so on. The final else
should call the following
line:
return super.action(event, arg);
so that if the action doesn't fit any of the ones we care about,
then it will be handed up to another level to be dealt with there.
Once all of the conditionals have been exhausted, we return true as
the last step in the action
method. This confirms that
the event has been handled successfully, in the case that it was an
event that we care about.
In most cases, more than one thing needs to happen in response to
the Event. In these cases, the corresponding if
clause
contains a single call to a method which handles the response. This
method contains all of the steps necessary to respond to the Event.
The idea here is to keep the main action
method clean,
with each response only taking up a single line of code within this
method.
Note that, in this problem, there are a couple of cases in which we can respond directly to the event without needing to create a separate method to handle the response.
Some particulars about the Color Choice menus:
For the cases in which the event is over the color Choice menus,
the responding methods will need the Object arg
from the
action
method's parameters. This arg
will
contain the value of the selection in the form of the String which is
displayed as the menu item. In particular, the String
"Color.blue"
might be this value, if that is the selected
color. The responding method needs to check to see if
arg
matches each of these Strings, and then set the
instance variable (selectedBodyColor
or
selectedTailColor
) to be the corresponding Color.
The responding method for this set of actions should also set the background color of the Choice menu to reflect the new selected color.
Some particulars about using the TextFields:
True to the name, TextFields are areas where text can be entered by
your user. The problem with this, in our case, is that we need
integers from the user. We assume that the user is intelligent and
will enter numbers into our TextFields, but we still need to convert
that text into Integers for the methods which need int
s.
To do this, we use the Integer
method
parseInt
, which we used in some of our List problems
earlier this semester.
In this problem, we apply Integer.parseInt
to the
result of getText()
, a method of TextField. Thus, each
time we need an integer from a TextField, we use something like
this:
int myInt = Integer.parseInt(myTextField.getText());
Some particulars about the resetAction method:
The resetAction()
method basically needs to clear the
Canvas so that the GUI can begin anew. We do this by first "erasing"
the Canvas by drawing a white rectangle over its entirety. For this,
we need the exact dimensions of our Canvas. Fortunately, a method
exists which gives us exactly this information.
We introduce a class called Dimension
which contains
width
and height
. (You do not need to
define the Dimension class. It already exists.) The Canvas method
size()
returns a Dimension object, from which we can
extract the exact dimensions of our Canvas. The syntax looks
like:
Dimension d = myCanvas.size();
We can then use d.width
and d.height
to
draw our white rectangle.
Remember that, in order to draw to the Canvas, we must have its Graphics context. We can get the Graphics context by using:
Graphics myContext = myCanvas.getGraphics();
With the Canvas "erased", we can then call the start()
method to restart the applet from its beginning.
Once you are done, your default Fish will react to the swim button like this:
This is what the applet window looks like after you've changed all the values to the ones shown (and clicked on the corresponding buttons to get it to actually change), and then clicked the swim button.