Java Interface, Abstract Class, and Event-Driven Animations Week 8 IAT-265, Fall 2009 Instructor: Eric Yang SIAT SFU Surrey 1 About Midterm & Final Exam Reduce the Midterm from 15% to 10% of your final grade Add an assignment to account for 5% of your final grade May use your final exam to override it if it turns out to make you better off Must be done individually and students will be asked how & why each question is done in person Final exam, as specified in Syllabus, must be attained an passing grade (50%) in order to obtain a clear pass (C- or better) - strictly enforced!! 2 Today’s topics The concept of Interface in Java Implementing an Interface Benefits of Interfaces Abstract Class Comparison of Interfaces and Abstract Classes Timer-Based Animation 3 The concept of Interface in Java A group of declared methods with no method bodies (i.e. { … }) associated with them, and classes can promise to implement it Example: public interface Mover { boolean changeGear(int newValue); void speedUp(int increment); void applyBrakes(int decrement); void move(); } class MountainBike extends Bicycle implements Mover { // You must implement here ALL the methods defined in Mover } The methods of an interface are also called abstract methods because it only declares signatures without implementations 4 Why Interface? Classes let us group similar objects together Inheritance lets us group similar classes together major goal is code reuse Sometimes we’d like to group together objects that are related only because they all share some common behaviours E.g. think about humans, birds, ants, space aliens, and robotics, what are the common behaviour among them? Is it appropriate to give them a single superclass? 5 Interface: Group Objects with the Same Behaviours Java’s interface specifies a set of responsibilities (in other words – a role) If a class promise to implement an interface, it must implement every method declared in the interface The interface provides an description of the capabilities it has There is no code sharing involved with interface, as each class has to implement its own version of the methods declared A class can implement many interfaces, separated by commas – a way to break single-parent inheritance mode and build multiple is-a relationships: TalentedPerson extends Person implements Walker, Pilot, Friend, Musician { … } 6 Case study: An Interface for Shape Classes Creating classes to represent rectangles, circles, and triangles and compute their area and a perimeter It may seem as though there is an inheritance relationship here, because rectangle, circle, and triangle are all shapes But code sharing isn’t useful in this case because each shape computes its area and perimeter in a totally different way 7 Define Interface Shape A better solution would be to write an interface called Shape to represent the common functionality of all shapes: the ability to compute an area and a perimeter // A general interface for all shape classes public interface Shape { public double getArea(); public double getPerimeter(); } An interface cannot be instantiated. In our case, any code trying to create a new Shape() would not compile It is, however, legal to create variables of type Shape that can refer to any object that implements the Shape interface 8 Implementing an Interface We must do two things: Declare that a class “implments” the interface Implement each of the interface’s methods in the class The general syntax for declaring that a class implements interfaces is the following: public class <name> implements <interface name>, <interface name>, …, <interface name> { . . . } 9 class Rectangle implements interface Shape public class Rectangle implements Shape { private double width; private double height; // Constructs a new rectangle with the given dimensions. public Rectangle(double width, double height) { this.width = width; this.height = height; } // Returns the area of this rectangle. public double getArea() { return width * height; } // Returns the perimeter of this rectangle. public double getPerimeter() { return 2.0 * (width + height); } } 10 class Circle implements interface Shape public class Circle implements Shape { private double radius; // Constructs a new circle with the given radius. public Circle(double radius) { this.radius = radius; } // Returns the area of this circle. public double getArea() { return Math.PI * radius * radius; } // Returns the perimeter of this circle. public double getPerimeter() { return 2.0 * Math.PI * radius; } } 11 class Triangle implements interface Shape public class Triangle implements Shape { private double a; private double b; private double c; // Constructs a new Triangle given side lengths. public Triangle(double a, double b, double c) { this.a = a; this.b = b; this.c = c; } As per Heron’s formula, the area of a triangle with sides of length a, b, and c is related to a value s equal to half the triangle’s perimeter: // Returns this triangle's area using Heron's formula. public double getArea() { double s = (a + b + c) / 2.0; return Math.sqrt(s * (s - a) * (s - b) * (s - c)); } // Returns the perimeter of this triangle. public double getPerimeter() { return a + b + c; } } 12 Benefits of Interfaces Classes that implements a common interface form a type hierarchy similar to those created by inheritance The interface serves as a parent type for the classes that implement it The major benefit of interfaces is that we can use them to achieve polymorphism 13 Polymorphism – Its 2nd Meaning Parent class or interface can be used as the declared type of its subclasses E.g. if we have an interface Mover (with a method move() declared) that is implemented by classes AirPlane, Whale, and Bicycle, we can then write: Mover mover = new AirPlane(); or Mover mover = new Whale (); or Mover mover = new Bicycle (); If we send the message mover.move(); The variable will move according to its actual type: AirPlane: fly in the sky, Whale: swim, and Bicycle: roll 14 Polymorphism in Action Allow us to do unified processing to objects of different types: Create an array of Shape and then process using loops Define a Shape as parameter to a method Return a Shape from a method public class ShapesMain { public static void main(String[] args) { Shape[] shapes = new Shape[3]; shapes[0] = new Rectangle(18, 18); shapes[1] = new Triangle(30, 30, 30); shapes[2] = new Circle(12); for (int i = 0; i < shapes.length; i++) { System.out.println("area=" + shapes[i].getArea() + ", perimeter=" + shapes[i].getPerimeter()); } } } 15 Abstract Class First let’s look at an example, and then we talk about why we need a class type – Abstract Class in Java Think about a class for all Animals, we can define a standard move method for them: public abstract class Animal { … public void move (Location location){ legs.moveForward(); … } } However, different animal types move in very different ways: Monkeys, Swans, Snakes, Penguins, … Makes a single standard implementation for all impossible 16 Why Abstract Class? When you want all the subclasses of a given class to define the same method, but there is no standard implementation, the solution is to define an abstract class that incorporates an abstract method 17 Syntax for Abstract Class In Java, a class that contains an abstract method must itself be declared as an abstract class, like this: public abstract class Animal { … public abstract void move (Location location); } An abstract method is one declared without an implementation (i.e. no method body { … }) Different from interface, abstract class’ abstract methods must use the abstract keyword 18 Annotations for Abstract Class An abstract class is one declared abstract: An abstract class doesn’t have to contain any abstract method When a class contains an abstract method, it must be declared as abstract Abstract class cannot be instantiated, but can be used as superclass Like interface, it can serve as declared type for its subclasses’ objects to realize polymorphism 19 Object AWT Abstract Classes in AWT & Swing Component Container Window Frame JFrame Class Layout manager classes are in the AWT Abstract Class Swing JComponent AbstractButton JPanel JLabel JMenuBar JTextComponent JMenuItem JButton JMenu JTextArea JTextField 20 Comparison of Interfaces and Abstract Classes 21 Timer-Based Animation The basic idea behind animation: Draw a graphical image over and over with slight changes from time to the next, so that it looks as though: Moving Changing size, angle, color, etc. To make this work, Java provides a Timer object javax.swing.Timer 22 How Java Timer works javax.swing.Timer works like a metronome: Once we start it, it keeps on going until we stop it While going, it provides a steady “ticking” that only the program can hear On each tick, certain actions that we can specify are performed To understand how this work, you need to know Java Event Model 23 The Java Event Model Some source objects (timer, button, window, mouse, etc.) fire Events Events: timer ticks; user presses a button or selects a menu item, opens a window, clicks a mouse, … Any object interested in hearing about a particular event can register with the event source as a listener When the event happens, Java notifies the listeners automatically Each listener decides how it will respond with its event handler method(s) 24 The Java Event Model (2) 25 Event-Handling Code 1. 2. 3. Create a source (some object that generates an event, like a Timer or its subclass) Create a middleman object called a listener that registers with the source Create one or more responders objects that will respond to the event 26 Example: 1. Define an Event Source: MoveTimer /** * MoveTimer.java * A subclass of javax.swing.Timer that can be used for animation. * It also serves as an example of the code for an "event source" object. */ public class MoveTimer extends Timer { private Mover _mover; // peer object public MoveTimer (int anInterval, Mover aMover) { super(anInterval, null); •Mover – an interface - is _mover = aMover; this.addActionListener(new MoveListener(_mover)); the object that responds to } MoveTimer } •Any instance of a class that implements the Mover can play this role 27 Annotations for MoveTimer Signature of Timer Constructor: Timer(int delay, ActionListener listener) Parameters: delay – time interval between ticks (in milliseconds, 1 sec = 1000 milliseconds) listener - an initial listener; can be null 28 2. Create a listener that registers with the source this.addActionListener(new MoveListener(_mover)); This statement create a MoveListener object, and pass Mover object to it, and register it as ActionListener with MoveTimer public class MoveListener implements java.awt.event.ActionListener { private Mover _mover; public MoveListener (Mover aMover) { super(); _mover = aMover; } public void actionPerformed(java.awt.event.ActionEvent e){ _mover.move(); } } 29 Annotations for ActionListener Defined in java.awt.event package public interface ActionListener extends EventListener{ actionPerformed(ActionEvent e); } The only thing the ActionListener interface requires is an actionPerformed method actionPerformed method is executed on each beat of the MoveTimer All it does here is to forward a message to the responder: _mover.move(); 30 3. Create responders - objects that will respond to the event These objects must know how to move, i.e. with a move method implemented A bouncing ball, a swimming fish, a moving ladybug We enforce this feature by defining an interface – Mover, and requires these objects implement it /* Mover.java * Interface for objects that can move to a specified location. * Must be implemented by objects that respond to a MoveTimer. */ public interface Mover { public void move(); } 31 Using MoveTimer for animation: Make a Ball Bounce - BallApp ** * BallApp.java * Displays a window with a red circle on a white background. */ public class BallApp extends javax.swing.JFrame { public BallApp (String title) { super(title); this.setSize(600, 450); this.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); this.add(new BallPanel()); this.setVisible(true); } public static void main (String [ ] args) { BallApp app = new BallApp ("BallApp"); } } 32 Using MoveTimer for animation: Make a Ball Bounce - BallPanel /* BallPanel.java * Creates the panel to be placed inside the BallApp window. */ public class BallPanel extends javax.swing.JPanel implements Mover { private final int INIT_X = 75; // attributes private final int INIT_Y = 75; private final int DIAMETER = 60; private final int INTERVAL = 100; private BouncingBall _ball; // components private MoveTimer _timer; public BallPanel () { super(); _ball = new BouncingBall (java.awt.Color.red, this); _timer = new MoveTimer(INTERVAL, this); this.setBackground(java.awt.Color.white); _ball.setLocation(INIT_X, INIT_Y); _ball.setSize(DIAMETER, DIAMETER); _timer.start(); } 33 Using MoveTimer for animation: Make a Ball Bounce – BallPanel (2) public void move() { _ball.move(); this.repaint(); } public void paintComponent (java.awt.Graphics aBrush) { super.paintComponent(aBrush); java.awt.Graphics2D betterBrush = (java.awt.Graphics2D) aBrush; _ball.fill(betterBrush); } } The BallPanel class contains a MoveTimer. When instantiate MoveTimer we need to make two decisions: How often it ticks (100 milliseconds in this case, framerate = 1000/100=10 fps) what resopnder object should be register with it (better use BallPanel to coordinate potential more than one animated object 34 Using MoveTimer for animation: Make a Ball Bounce – BouncingBall /** * BouncingBall.java * Extends ActiveEllipse, adding the ability to "bounce." */ public class BouncingBall extends ActiveEllipse implements Mover { private int _changeX, _changeY; // attributes private final int MOVE_LEN = 5; private javax.swing.JPanel _panel; // peer object (and container) private javax.swing.Timer _timer; public BouncingBall (java.awt.Color aColor, javax.swing.JPanel aPanel){ super(aColor); _changeX = MOVE_LEN; _changeY = MOVE_LEN; _panel = aPanel; } //Methods so the BouncingBall knows how to move 35 Using MoveTimer: Make a Ball Bounce – BouncingBall (2) public void move() { int nextX = (int)this.getX() + _changeX; int nextY = (int)this.getY() + _changeY; this.setLocation(nextX, nextY); } If we don’t consider the bouncing on boundary situation, just make the ball move, the implementation above is good enough So for each ball’s move: we get the ball’s current position along x by calling this.getX() and add the displacement _changeX; we get the ball’s current position along y by calling this.getY() and add the displacement _changeY; Reset its location using the new position value: this.setLocation(nextX, nextY); 36 As it is a bouncing ball … We must consider the ball’s bouncing on the bounds of the window x •When ball hits panel’s Min Bound X reverse •When ball hits panel’s Min Bound Y reverse •When ball hits panel’s Max Bound X reverse •When ball hits panel’s Max Bound Y reverse y 37 BouncingBall (2) – Adding Conditional Check for Panel’s Bounds public void move() { int nextX = (int)this.getX() + _changeX; int nextY = (int)this.getY() + _changeY; if (nextX <= this.getMinBoundX()) { _changeX *= -1; nextX = this.getMinBoundX(); } else if (nextX >= this.getMaxBoundX()) { _changeX *= -1; nextX = this.getMaxBoundX(); } if (nextY <= this.getMinBoundY()) { _changeY *= -1; nextY = this.getMinBoundY(); } else if (nextY > this.getMaxBoundY()){ _changeY *= -1; nextY = this.getMaxBoundY(); } this.setLocation(nextX, nextY); } 38 Calculate the Ball’s Bounds … As (nextX, nextY) are about the upper-left corner’s coordinates, so we must calcuate Ball’s bounds relative to it x •MinBoundX = panel’s x •MinBoundY = panel’s y • MaxBoundX = panel’s x + panel width – ball’s width •MaxBoundY = panel’s y + panel height – ball’s height y 39 BouncingBall (3) – Adding get methods for Min- & Max Bounds public int getMinBoundX() { return (int) _panel.getX(); } public int getMinBoundY() { return (int) _panel.getY(); } public int getMaxBoundX() { return (int) (_panel.getX() + _panel.getWidth() - this.getWidth()); } public int getMaxBoundY() { return (int) (_panel.getY() + _panel.getHeight() - this.getHeight()); } } 40