CannonWorld, Event-driven Programming, and Border Layout

advertisement
Session 9
CannonWorld, Event-driven
Programming, and Border Layout
The CannonWorld
Budd has added two new objects to our cannon game:
• a button at the top of the window. When the user presses
the button, the cannon fires a cannonball.
• a slider at the right. When the user adjusts the position of
the slider, the cannon changes the angle at which it fires.
An Example: The CannonWorld
The user can cause these events at any
time. The user controls the flow of the
program, not the game world.
Control of the game changes from
“Do this , then that, then this other thing.”
to
“Respond to the user’s action.”
Event-Driven Programming
Object-oriented programming shifts program
control from a top-level “main” program
into a set of collaborating objects.
This new emphasis also makes it easier for
us to write programs that shift control from
the program to the user.
Event-Driven Programming
This style of programming is called event-driven
because it builds program control around one or
more events that the user causes. The program
retains low-level control of how to respond to
each kind of event that the user can initiate.
Event-driven programming can also be done in
environments with little or no user interaction. In
such environments, the events are generated by
other programs: objects that generate events to
request services.
Event-Driven Programming
In Java, the programmer defines objects called listeners that wait for
and respond to user-initiated events.
A listener can be attached to any object capable of generating an event
caused by the user:
• the mouse
– moving the mouse
– pressing and releasing mouse buttons
• the keyboard
– pressing any key
• active components such as buttons and sliders
We can also attach listeners to non-UI components, but we won’t write
that sort of program until much later in the semester.
Listeners in the CannonWorld
Each GUI component needs a listener to wait for
the user to manipulate and then relay the event to
the CannonWorld.
private Scrollbar slider;
private class ScrollBarListener implements AdjustmentListener {
public void adjustmentValueChanged( AdjustmentEvent e ){
angle = slider.getValue();
message = "Angle: " + angle;
repaint();
}
}
Listeners in the CannonWorld
private class FireButtonListener implements ActionListener {
public void actionPerformed( ActionEvent e ) {
double radianAngle = angle * Math.PI / 180.0;
double sinAngle = Math.sin(radianAngle);
double cosAngle = Math.cos(radianAngle);
cannonBall = new CannonBall( 20 + (int) (30 * cosAngle),
dy(5+(int) (30 * sinAngle)),
5,
12 * cosAngle,
-12 * sinAngle );
repaint();
}
}
Listeners in the CannonWorld
public CannonWorld() {
setSize ( FrameWidth, FrameHeight );
setTitle( "Cannon Game" );
Button fire = new Button( "fire" );
fire.addActionListener( new FireButtonListener() );
add( "North", fire );
slider = new Scrollbar( Scrollbar.VERTICAL, angle, 5, 0, 90 );
slider.addAdjustmentListener( new ScrollBarListener() );
add( "East", slider );
}
Listeners as Inner Classes
What is an inner class?
Any class defined within another class definition:
public class CannonWorld extends Frame {
...
private class FireButtonListener ... {
...
}
...
}
How do we create one?
“Just do it.”
Why do you suppose FireButtonListener is private?
Listeners as Inner Classes
Why do we create them?
• For convenient access to the private
members of the outer class.
• For simple collaboration between pure
masters and slaves.
• Almost only for listeners.
Notice that one .java file can produce many
.class files.
Listeners Implement Interfaces
Examples
• ScrollBarListener implements AdjustmentListener
• FireButtonListener implements ActionListener
Review: What is an interface?
• A list of responsibilities.
• A set of messages to which an object promises to
respond.
• Sometimes called a protocol.
• Like a class with no behavior.
Why Use Interfaces
Why do we use interfaces in this program?
• When the user presses a button, the Java runtime system sends an actionPerformed()
message to any object that is listening for the
button’s events. If we want our listener to listen,
it must listen for that particular message.
• When the user adjusts a slider, the Java run-time
system sends an adjustmentValueChanged()
message to any object that is listening for the
slider’s events. If we want our listener to listen, it
must listen for that particular message.
Why Use Interfaces
More generally, why do we use interfaces?
• To allow our objects to work inside an
existing framework.
• To allow programmers to create objects
that fulfill responsibilities — without
committing to how their objects do so!
Layout Managers
• Frame is a subclass of the Container class
– so it can hold objects such as buttons, scroll
bars, etc.
– layout manager assigns locations to these
objects within the container
– the default LayoutManager is BorderLayout
North
West
Center
South
East
Layout Managers
• Five standard types of layout managers:
– BorderLayout
– GridLayout - creates an rectangular array of
components
– FlowLayout - places components in rows left to
right, top to bottom
– CardLayout - stacks components vertically with
only one visible at any one time
– GridBagLayout - most general, but most
complex. It allows for a nonuniform grid of
squares with components placed in various
positions within each square.
An Exercise
Add to our CannonWorld a button that
allows the user to change the color of the
cannonball from blue to red to yellow to
blue....
Place the button on the lefthand side of the
window.
Steps to the solution:
1. Add a button to the CannonWorld.
2. Add a listener class to CannonWorld.
The listener’s actionPerformed method needs to tell the ball
to take the next color. It could have an if-statement that
toggles the colors in sequence, but...
• Shouldn’t the ball be controlling its own color, rather than
the application using the ball?
So in my solution, I decided to have the CannonBall respond
to a nextColor() message and toggle its own color.
More Steps to the Solution
The next question is, do I add a nextColor() method directly to the
CannonBall class, or do I create a subclass?
In general, if we need a new kind of object, then we should create a
new kinds of object.
(If a particular method turns out to be more generally useful than we
anticipate, then we can always refactor the solution so that the
method lives higher in the class hierarchy.)
So:
3. Implement a ChangingCannonBall class.
4. Use instances of ChangingCannonBall in the CannonWorld.
Using GridLayout
• MemoPad uses GridLayout exclusively, but
it nests GridLayouts:
– MemoPad frame is GridLayout( 3, 1 )
• top row contains a Panel with GridLayout( 2, 2 )
• middle row contains a Panel with GridLayout( 1, 3 )
Using GridLayout
– MemoPad frame is GridLayout( 3, 1 )
Using GridLayout
public class MemoPad extends CloseableFrame
{
...
public MemoPad()
{
database = new DefaultMemoDatabase();
setLayout( new GridLayout( 3, 1 ) );
setSize( 300, 140 );
setTitle( "Memo Pad " );
fieldPanel = new FieldPanel();
fieldPanel.setSize( 300, 80 );
add( fieldPanel );
buttonPanel = new ButtonPanel( this );
buttonPanel.setSize( 300, 30 );
add( buttonPanel );
messagePanel = new MessagePanel( ".. No messages .." );
messagePanel.setSize( 300, 30 );
add( messagePanel );
}
Using GridLayout
public class FieldPanel extends Panel
{
private TextField keyField;
private TextField valueField;
public FieldPanel()
{
setLayout( new GridLayout( 2, 2 ) );
keyField
= new TextField( 20 );
valueField = new TextField( 20 );
add(
add(
add(
add(
}
...
new Label( "Key:" ) );
keyField );
new Label( "Value:" ) );
valueField );
Using GridLayout
public class ButtonPanel extends Panel {
private MemoPad memos;
public ButtonPanel( MemoPad p ) {
memos = p;
setLayout( new GridLayout( 1, 3 ) );
Button insertButton = new Button( "Insert" );
insertButton.addActionListener( new InsertButtonListener() );
add( insertButton );
Button findButton = new Button( "Find" );
findButton.addActionListener( new FindButtonListener() );
add( findButton );
Button removeButton = new Button( "Remove" );
removeButton.addActionListener( new RemoveButtonListener() );
add( removeButton );
}
...
Using Panels with BorderLayout
• BorderLayout seems very restrictive, but
you can use a panel to hold several
components in each “direction”.
An Exercise
Place the “change color” button in a Panel
with the “fire” button along the top of the
window.
Test 1
• Tuesday, Feb. 14 (next week)
• Chapters: 1, 2, 3, 4, 5, 11, 14 (some file
stuff)
• Test format: closed book, except one
8.5”x11” sheet of paper (both sides)
Study Hints
1. Go through each chapter and making a
list of the vocabulary terms that we have
discussed. Could you explain what each
means and how they relate to each other?
2. Review the slides I used during class
and consider the points I have
emphasized either directly on the slides or
in addition to the slides.
Study Hints
3. Review the programs we have worked with (MemoPad,
Accumulator, LunarLander, Ball and BallWorld,
CannonWorld, etc). I will provide you with any code I
expect you to use/modify, but you don’t want to waste
test time reviewing how the code actually works.
4. Read through the questions at the end of the
chapters. Play the "second guess” the instructor game.
That is, think about what you reviewed in the previous
steps and think about how well each question would fit
into these topics. Some of my questions will come from
these questions. Others will be modifications to these
questions based more on what I have chosen to
emphasize.
Download