Session 10 CannonGame and Event-driven Programming The CannonGame Application • • • • • • • • What color is the cannon ball? What is the role of dy()? How does the CannonGame draw the cannon? What do lv, lh, sv, and sh mean? What about sx and sy? How does the cannon ball follow the prescribed angle, when we don’t pass the angle to the cannon ball? How does the cannon ball reverse direction? How does the game know that the ball has hit something (either the target or the floor)? How does the program terminate? The CannonGame Application • Let’s go to the tape, Jim… 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 this semester. An Example: 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.” Listeners in the CannonWorld Each 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. Listeners Implement Interfaces Examples • ScrollBarListener implements AdjustmentListener • FireButtonListener implements ActionListener 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. Listeners Implement Interfaces How do we create one? Just like a class, without the method bodies: public interface AdjustmentListener { public void adjustmentValueChanged( AdjustmentEvent e ); } 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! 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. 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. I could have written an if expression that toggles the colors in sequence, but... • Shouldn’t the ball be controlling its own color, rather than the application using the ball? So I decided to have the CannonBall respond to a nextColor() message and toggle its own color. More on a Solution to the Exercise 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. 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. Using Panels with BorderLayout • BorderLayout seems very restrictive, but you can use a panel to hold several components in each “direction”.