banner



How To Register Mousepressed Events Only On Part Of The Canvas

Chapter three
Animation and Interactivity

Even though the programs in Chapter 2 offer a reasonably consummate survey to the classes in the acm.graphics package, they do so using examples that are entirely static. Running those programs causes a moving-picture show to appear in its final course. For students to become excited most graphics, it is essential to add animation so that the pictures evolve as the program runs and interactivity to give the user command over the program. This chapter introduces several strategies for implementing each of those capabilities.

As with almost every programming task, nevertheless, there are many different ways to animate a program or to go it to reply to mouse events. Some instructors will strongly prefer i style, while others will contend equally strongly for a different approach. To reach the widest possible audition, the Java Task Force chose to back up several of the most popular styles and allow private instructors to make their own choices.

Although the decision to back up multiple styles seems appropriate in terms of the overall package design, it carries with it some pedagogical risks. Giving students several options for accomplishing the aforementioned task oftentimes confuses them to the point that they acquire none of the strategies well. In general, it is more than successful to teach one arroyo in detail, bringing upwardly the possibility of alternative strategies just when students have mastered a particular approach. To avert the same pitfalls for readers of this tutorial, we have chosen to foreground i strategy for animation and one for mouse-based interaction and to identify the discussion of alternative strategies in an optional section. As you read this affiliate for the beginning time, it probably makes sense to focus on sections 3.one and iii.ii, leaving the word of culling strategies in section iii.three for a subsequent rereading.

iii.1 Graphical animation

In calculator graphics, the process of updating a graphical brandish so that information technology changes over time is chosen animation. Implementing animation typically involves displaying an initial version of the picture and then changing it slightly over time and so that the individual changes announced continuous from one version of the picture to the next. This strategy is analogous to classical film animation in which cartoonists break up the motion of the scene into a series of separate frames. The difference in time between each frame is called a fourth dimension step and is typically very curt. Movies, for case, typically run at 30 frames a second, which makes the fourth dimension stride approximately 33 milliseconds. If you desire to obtain smooth movement in Java, yous need to employ a time step around this scale or even faster.

A simple example of animation

The easiest way to breathing graphical programs is to include a loop in your run method that updates the moving-picture show from i frame to the next and then pauses for the duration of the time footstep. An example of this fashion of blitheness appears in Effigy 3-1, which moves a GLabel across the screen from right to left, just the mode the headline displays in New York's Times Square do.

Figure 3-1. Lawmaking to motility text across the screen [applet]

                                          /*  * File: TimesSquare.java  * ----------------------  * This programme displays the text of the string HEADLINE on the  * screen in an animated way that moves it across the brandish  * from left to correct.  */                import acm.graphics.*; import acm.program.*;   public form TimesSquare extends GraphicsProgram {                /** Runs the plan */                public void run() {       GLabel label = new GLabel(HEADLINE);       characterization.setFont("Serif-72");       add(label, getWidth(), (getHeight() + label.getAscent()) / 2);       while (label.getX() + characterization.getWidth() > 0) {          label.move(-DELTA_X, 0);          intermission(PAUSE_TIME);       }    }                /* The number of pixels to shift the label on each cycle */                private static final int DELTA_X = ii;                /* The number of milliseconds to break on each cycle */                private static final int PAUSE_TIME = twenty;                /* The string to employ as the value of the label */                private static final String HEADLINE =      "When in the grade of homo events information technology becomes necessary " +      "for one people to dissolve the political bands which " +      "connected them with another . . .";   }                      

The TimesSquare program in Figure 3-1 begins by creating a GLabel object and positioning information technology then that it is centered vertically in the window. Its starting point in the horizontal dimension, nevertheless, is merely at the right edge of the canvas, which ways that the entire label is outside the visible surface area of the canvas. The animation is achieved by the following lines:

                                                                  while (characterization.getX() + label.getWidth() > 0) {    characterization.move(-DELTA_X, 0);    pause(PAUSE_TIME); }                                                            

This lawmaking loops until the label has moved entirely past the left border of the display, shifting it DELTA_X pixels to the left on every time step. The call to pause(PAUSE_TIME) within the loop causes the programme to suspend operation for PAUSE_TIME milliseconds. This call is necessary to achieve the effect of animation, because computers run and so chop-chop that the label would instantly cipher off the left side of the window if you didn't slow things downwards.

Bouncing a brawl

A slightly more than sophisticated application of animation appears in Effigy three-2. This program bounces a ball around the walls of the graphics window and forms the foundation for such classic video games as Pong or Breakout. Because a static picture in this text would offer trivial insight into how such an animated program works, it is useful to run this as an applet. If yous are reading this tutorial on the JTF web site, you tin can bring up the applet in a carve up window by clicking on the applet mark in the caption, just you tin as well run any of the applets from the demo site at

http://www.acm.org/jtf/demos/index.html

Figure 3-2. Plan to bounce a brawl off the boundaries of the sail [applet]

                                          /*  * File: BouncingBall.java  * -----------------------  * This file implements a simple bouncing ball using the run method  * to bulldoze the animation.  */                import acm.graphics.*; import acm.program.*;   public class BouncingBall extends GraphicsProgram {                /** Initialize the ball and its velocity components */                public void init() {       ball = new GBall(BALL_RADIUS);       add together(ball, getWidth() / 2, getHeight() / 2);       dx = ii;       dy = ane;    }                /** Run forever bouncing the ball */                public void run() {       waitForClick();       while (true) {          advanceOneTimeStep();          pause(PAUSE_TIME);       }    }                /* Check for bounces and accelerate the ball */                individual void advanceOneTimeStep() {       double bx = ball.getX();       double by = ball.getY();       if (bx < BALL_RADIUS || bx > getWidth() - BALL_RADIUS) dx = -dx;       if (by < BALL_RADIUS || by > getHeight() - BALL_RADIUS) dy = -dy;       ball.motility(dx, dy);    }                /* Private constants */                private static concluding double BALL_RADIUS = 10;    private static final int PAUSE_TIME = twenty;                /* Private instance variables */                private GBall ball;                /* The ball object                   */                private double dx;                /* Velocity delta in the ten direction */                private double dy;                /* Velocity delta in the y direction */                }                      

The code in Figure iii-two uses the GBall class presented in Figure 2-xviii to create a brawl whose reference point is at the heart. Doing so makes the geometric calculation simpler when checking whether a bounciness occurs considering all four edges can exist treated symmetrically. The program code is also divided between the init method, which creates the ball and adds it to the window, and the run method, which runs the animation. The code for the run method is

                                                                  public void run() {    waitForClick();    while (true) {       advanceOneTimeStep();       pause(PAUSE_TIME);    } }                                                            

which is almost precisely the paradigmatic for an animation loop. The new statement is the call to the waitForClick method, which is implemented by GraphicsProgram and suspends the program until a mouse click occurs in the graphics canvas. This call means that the program does not showtime up immediately, but instead waits for a mouse click before proceeding.

The lawmaking that implements the underlying physics of the animation appears in the private method advanceOneTimeStep . This method checks to come across whether the ball has reached 1 of the edges of the canvass, in which example it changes the sign of the advisable component of the ball's velocity, which is stored in the variables dx and dy . It then moves the ball by those displacements to update its position on the display.

Simulating randomness in animations

Every bit written, the bouncing ball program from the preceding section is altogether too anticipated. The ball begins with a constant velocity and then makes perfectly reflective bounces off the edges of the canvas, tracing the same trajectory each time. Many blithe programs volition involve some kind of random beliefs, and students volition quickly want to know how they tin can implement random processes in their own code.

Although it is certainly possible to use either the Math.random method or the Random class in java.util for this purpose, in that location are a couple of pedagogical advantages to using the RandomGenerator class in the acm.util package instead:

  1. The name of the class emphasizes that a RandomGenerator object is a generator for random values and not a random value in itself. When students use the Random class, they are much more likely to create a new Random instance for each value they wish to generate.
  2. The RandomGenerator class offers several additional methods that are oft much easier to use than those in the base of operations class. These extended methods are listed in Figure 3-five.

Effigy 3-5. Useful methods in the RandomGenerator form

 Manufacturing plant method

static RandomGenerator getInstance()
Returns a standard random generator.


 Methods inherited from the Random class in java.util
int nextInt(int n)
Returns a random integer chosen from the n values in the range 0 to north - one, inclusive.
double nextDouble()
Returns a random double d in the range 0 � d< one.
void nextBoolean()
Returns a random boolean that is true approximately 50% of the time.
void setSeed(long seed)
Sets a "seed" to signal a starting point for the pseudorandom sequence.

 Additional methods defined past RandomGenerator
int nextInt(int low, int loftier)
Returns a random integer in the specified range (inclusive).
double nextDouble(double depression, double loftier)
Returns a random double in the specified range.
boolean nextBoolean(double p)
Returns a random boolean that is true with probability p (0 = never, 1 = always).
Color nextColor()
Returns a random opaque color.

The conventional design for using the RandomGenerator class is to declare and initialize an instance variable to hold the generator using the line

                                                                  private RandomGenerator rgen = RandomInteger.getInstance();                                                            

Once this declaration is made, every method in this form tin can then generate new random values by invoking the appropriate method on the rgen variable. For case, you could use this strategy in the BouncingBall program to initialize each velocity component of the ball to a random value between –three and 3:

                                                                  dx = rgen.nextDouble(-3, 3); dy = rgen.nextDouble(-three, 3);                                                            

The RandomShapes program in Effigy 3-6 makes more extensive use of the facilities of the RandomGenerator class. The plan generates ten shapes and positions them on the canvas using randomness in each of the post-obit means:

  • The shapes are randomly called to be rectangles, ovals, or stars. The stars are represented internally using the GStar form defined in Figure two-15 from Chapter 2.
  • The shapes are given a random size that ranges between MIN_SIZE and MAX_SIZE in each dimension.
  • The shapes are positioned randomly on the sheet subject area to the condition that the entire shape must fit inside the boundaries.
  • The shape is filled in a random colour.

A sample run of the RandomShapes plan might look similar this:

Most of RandomShapes plan in Figure iii-6 is reasonably straightforward, just there are withal a few aspects of the code that are easier to empathise with some boosted explanation:

  • The code for the run method includes a while loop that allows the user to generate a new set of shapes by clicking the mouse. The waitForClick method was introduced before in the chapter in the word of the billowy ball programs and simply waits for a mouse click.
  • The calculation of the random coordinate positions seems slightly more circuitous that necessary. At kickoff glance, information technology would seem as if one could ensure that the unabridged figure was inside the canvas by writing

                                                                                  double 10 = rgen.nextDouble(0, getWidth() - gobj.getWidth()); double y = rgen.nextDouble(0, getHeight() - gobj.getHeight());                                                                        

    While that lawmaking would be sufficient for the GRect and GOval objects that have their reference point in the upper left corner, it doesn't work for figures like GStar for which the reference signal is inside the figure. The getBounds method returns the actual bounding box of the figure, which ways that gobj.getBounds().getX() returns the actual x coordinate of the left edge of the figure. You can brand sure that the figure fits on the screen by adjusting the coordinates to compensate for the shift in origin.

The RandomGenerator grade from the java.util class has applications in a wide variety of contexts beyond graphical blitheness. In our feel it is far and abroad the most widely used grade in the java.util parcel.

Figure iii-half-dozen. Program to generate random shapes [applet]

                                          /*  * File: RandomShapes.coffee  * -----------------------  * This file creates x boxes, ovals, and stars at random locations  * on the screen, pausing for a suitable interval betwixt each i.  */                import acm.graphics.*; import acm.program.*; import acm.util.*;   public grade RandomShapes extends GraphicsProgram {                /** Runs the programme */                public void run() {       while (true) {          for (int i = 0; i < NOBJECTS; i++) {             addOneRandomShape();             interruption(PAUSE_TIME);          }          waitForClick();          removeAll();       }    }                /* Adds a random shape to the canvass */                private void addOneRandomShape() {       GObject gobj = createRandomShape();       gobj.setColor(rgen.nextColor());       if (gobj instanceof GFillable) ((GFillable) gobj).setFilled(true);       double x = rgen.nextDouble(0, getWidth() - gobj.getWidth())                    - gobj.getBounds().getX();       double y = rgen.nextDouble(0, getHeight() - gobj.getHeight())                    - gobj.getBounds().getY();       add(gobj, 10, y);    }                /* Generates a random shape whose reference indicate is the origin */                private GObject createRandomShape() {       double width = rgen.nextDouble(MIN_SIZE, MAX_SIZE);       double top = rgen.nextDouble(MIN_SIZE, MAX_SIZE);       switch (rgen.nextInt(3)) {         case 0: return new GRect(width, meridian);         case ane: return new GOval(width, height);         example 2: return new GStar(width);         default: throw new ErrorException("Illegal shape index");       }    }                /* Private constants */                individual static terminal int NOBJECTS = 10;    private static final int PAUSE_TIME = 1000;    private static concluding double MIN_SIZE = 25;    private static last double MAX_SIZE = 150;                /* Private instance variables */                private RandomGenerator rgen = RandomInteger.getInstance(); }                      

3.two Interactivity

The animation capability presented in section 3.1 certainly helps to brand graphical programs more exciting, but it is not in itself sufficient to implement the kind of interactive graphical applications that today's students have come to expect. Interactive programs must also reply to deportment taken past the user. The sections that follow outline the Java event model and describe one strategy for responding to those events. Several other paradigms for event handling are described in section 3.3.

The Java event model

Programs like Add2Console that request input from the user are interactive programs of a sort. Console programs, however, ask the user for input just at sure well-defined points in the program's execution history when the program makes an explicit call to an input method similar readInt . This mode of interaction is called synchronous, because it is always in sync with the program functioning. Modern user interfaces, however, are asynchronous in that they allow the user to intercede at whatsoever betoken, typically past using the mouse or the keyboard to trigger a particular activeness.

Events that occur asynchronously with respect to the program performance—mouse clicks, key strokes, and the like—are represented using a construction called an event. When an issue occurs, the response is e'er the invocation of a method in some object that is waiting to hear about that event. Such an object is called a listener. In Coffee, objects that mind for user-interface events exercise so by implementing the methods in a specific listener interface, which is typically defined in the bundle java.awt.upshot . This bundle contains several interfaces that allow clients to respond to mouse clicks, button presses, keystrokes, changes in component sizes, and other asynchronous events. The examples in the next several examples concentrate on the interfaces that define how programs reply to mouse events, which are described in the following section.

Responding to mouse events

The java.awt.event package defines two split up interfaces— MouseListener and MouseMotionListener —that specify how a programme responds to mouse events. The MouseListener methods are called in response to actions that occur relatively infrequently, such every bit pressing a mouse button or moving the mouse entirely outside the boundary in which the listener is active. The MouseMotionListener methods are called whenever the mouse moves, which happens much more often. Moving the mouse without pressing the button results in calls to mouseMoved ; dragging the mouse with the button down results in calls to mouseDragged . The methods in each interface are listed in Figure three-three.

Effigy 3-3. Methods in the MouseListener and MouseMotionListener interfaces

 The MouseListener interface
void mousePressed(MouseEvent e)
Chosen whenever the mouse button is pressed.
void mouseReleased(MouseEvent east)
Called whenever the mouse button is released.
void mouseClicked(MouseEvent e)
Called when the mouse button is "clicked" (pressed and released within a short span of time).
void mouseEntered(MouseEvent e)
Called whenever the mouse enters the canvas.
void mouseExited(MouseEvent due east)
Chosen whenever the mouse exits the canvas.

 The MouseMotionListener interface
void mouseMoved(MouseEvent e)
Called whenever the mouse is moved with the button upwardly.
void mouseDragged(MouseEvent e)
Called whenever the mouse is moved with the push down.

Each of the methods listed in Figure 3-3 takes as its argument an object of type MouseEvent , which is defined in the parcel java.awt.event , just as the listener interfaces are. The MouseEvent form includes a rich set of methods for designing sophisticated user interfaces. For virtually applications, even so, you lot tin can get away with using only 2 of those methods. Given a MouseEvent stored in a variable named east , you tin can determine the location at which the mouse fifty-fifty occurred by calling due east.getX() and e.getY() .

The GraphicsProgram course declares itself to exist both a MouseListener and a MouseMotionListener by defining implementations for each of the listener methods in those interfaces. Those implementations, nevertheless, practise nix at all. For case, the default definition of mouseClicked is merely

                                                                  public void mouseClicked(MouseEvent e) {/* Empty */                        }                                                            

Thus, unless you override the definition of mouseClicked in your GraphicsProgram bracket, it will simply ignore mouse clicks, just as it ignores all the other mouse events. If, yet, you define a new mouseClicked method, the event handling organisation will call your version instead of the empty one. Because any methods that you lot don't override go along to do what they did past default (i.due east., nada), y'all merely take to override the listener methods you need.

Whenever you lot write event-handling code in Java, it is of import to remember that defining the listener methods is not sufficient in itself to found the listener relationship. You likewise need to brand sure that the object that is listening for events adds itself equally a listener to the object that is generating the events. In the case of a GraphicsProgram , the programme is doing the listening, and the embedded GCanvas is generating the events. You therefore need to take the plan register its involvement in events generated by the canvass past executing the following lines in the context of the program:

                                                                  getCanvas().addMouseListener(this); getCanvas().addMouseMotionListener(this);                                                            

To brand this operation only a little bit simpler—and to avoid having to explain the getCanvas method and the keyword this —the GraphicsProgram class includes a method addMouseListeners that performs precisely these two steps. The examples in the subsections that follow make use of this simplified class.

A line-drawing plan

The first example of mouse interaction is a uncomplicated line-cartoon programme that operates—at to the lowest degree for straight lines—in the style that painting programs like Adobe Illustrator� does. To create a line on the sail, you press the mouse at its starting point. From there, you hold the mouse button down and drag information technology to the other endpoint. Equally you lot do and so, the line keeps itself updated on the canvas then that it connects the starting point with the electric current position of the mouse.

Equally an instance, suppose that you lot press the mouse push somewhere on the screen then drag it rightward an inch, property the button down. What you'd similar to run into is the post-obit picture:

If yous then move the mouse down without releasing the push button, the displayed line will rails the mouse, and then that you might see the following picture:

When you release the mouse, the line stays where it is, and you tin can go alee and draw additional lines using the aforementioned sequence of operations.

Because the line joining the initial point and the mouse stretches and contracts equally you lot move the mouse, this technique is chosen safety-banding. The lawmaking for a line-drawing program that uses prophylactic-banding appears in Figure 3-4. Despite the fact that the program seems to perform a reasonably interesting task, the lawmaking is surprisingly brusk. The bodies of the three methods in the program incorporate a grand total of four lines. Fifty-fifty so, it is worth going through each of the methods in turn.

Figure iii-4. Program to create a line drawing on the screen [applet]

                                          /*  * File: DrawLine.coffee  * -------------------  * This program allows users to create lines on the graphics  * sheet past clicking and dragging with the mouse.  The line  * is redrawn from the original point to the new endpoint, which  * makes it look every bit if it is connected with a rubber ring.  */                import acm.graphics.*; import acm.programme.*; import java.awt.issue.*;                /** This form allows users to draw lines on the sail */                public class DrawLine extends GraphicsProgram {                /** Initializes the program by enabling the mouse listeners */                public void init() {       addMouseListeners();    }                /** Called on mouse printing to create a new line */                public void mousePressed(MouseEvent eastward) {       line = new GLine(e.getX(), e.getY(), e.getX(), e.getY());       add together(line);    }                /** Chosen on mouse drag to reset the endpoint */                public void mouseDragged(MouseEvent east) {       line.setEndPoint(east.getX(), e.getY());    }                /* Individual instance variables */                individual GLine line;   }                      

The starting time affair to notice is that this programme contains an init method rather than a run method. In this item case, you could call the method past either proper noun and accept the program run in exactly the aforementioned way, but you lot volition soon meet situations in which you demand to exist clear about the role of these two methods. Even though both are called as office of the program startup process, the two methods serve different conceptual purposes. The init method is intended for startup operations that are executed before the program starts; the run method is executed as part of the program operation. In the examples of animation earlier in the chapter, the run method implemented the animation. In this program, zippo is actually running after the program starts up. The just time things happen is when the user presses the mouse button and begins to drag information technology beyond the screen. Such programs are said to be upshot-driven. Issue-driven programs tend to operate by performing some amount of initialization and then waiting for events to occur. In this case, the only initialization necessary is to enable the program as a listener for events, which is achieved through the call to addMouseListeners .

The mousePressed method is called whenever the user presses the mouse button and overrides the empty definition implemented past the GraphicsProgram form itself. In the line-drawing program, the body of the mousePressed method simply creates a new GLine object that starts and ends at the current mouse position. This GLine appears on the canvas equally a dot.

The GLine is stored in the private instance variable line , which means that other methods in the class have access to information technology. In particular, dragging the mouse with the button downwards calls the mouseDragged method, which resets the endpoint of the line to the current mouse position.

Dragging objects on the sail

The second example is a flake more sophisticated simply still fits easily on a single page. The DragObjects program in Effigy 3-seven illustrates how to use mouse listeners to support dragging graphical objects effectually on the canvas. The lawmaking in the init method should seem familiar, given that its effect is to create two graphical objects—the red rectangle and the light-green oval from the FeltBoard program in Chapter 2—and and then add them to the canvas.

Figure three-7. Object-dragging program using the addMouseListeners method [applet]

                                          /*  * File: DragObjects.java  * ----------------------  * This implementation illustrates the technique of using the  * addMouseListeners method to register the program itself as  * a listeners for events in the underlying GCanvas.  */                import coffee.awt.*; import java.awt.effect.*; import acm.graphics.*; import acm.program.*;                /** This grade displays a mouse-draggable rectangle and oval */                public class DragObjects extends GraphicsProgram {                /** Initializes the program */                public void init() {       GRect rect = new GRect(100, 100, 150, 100);       rect.setFilled(true);       rect.setColor(Color.RED);       add(rect);       GOval oval = new GOval(300, 115, 100, 70);       oval.setFilled(true);       oval.setColor(Colour.Greenish);       add(oval);       addMouseListeners();    }                /** Chosen on mouse printing to record the coordinates of the click */                public void mousePressed(MouseEvent eastward) {       concluding = new GPoint(e.getPoint());       gobj = getElementAt(last);    }                /** Chosen on mouse drag to reposition the object */                public void mouseDragged(MouseEvent e) {       if (gobj != nada) {          gobj.move(e.getX() - last.getX(), east.getY() - last.getY());          last = new GPoint(eastward.getPoint());       }    }                /** Called on mouse click to move this object to the front */                public void mouseClicked(MouseEvent e) {       if (gobj != null) gobj.sendToFront();    }                /* Individual instance variables */                individual GObject gobj;                /* The object being dragged */                private GPoint terminal;                /* The concluding mouse position  */                }                      

The lawmaking in Figure 3-7 overrides three of the event methods. The commencement of these is mousePressed , which is called when the mouse push first goes downwardly. That method looks like this:

                                                                  public void mousePressed(MouseEvent e) {    lastX = eastward.getX();    lastY = e.getY();    gobj = getElementAt(lastX, lastY); }                                                            

The start two statements simply record the x and y coordinates of the mouse in the case variables lastX and lastY . The last statement in mousePressed checks to see what object on the sail contains the current mouse position. Here, it is of import to recognize that there are ii possibilities. First, you could be pressing the mouse push button on top of an object, which means that you want to showtime dragging it. Second, you could exist pressing the mouse button somewhere else on the canvas where there is no object to drag. The getElementAt method looks at the specified position and returns the object it finds there. If there is more than than one object covering that space, it chooses the one that is in front of the others in the stacking lodge. If there are no objects at all at the specified location, getElementAt returns the value goose egg .

The mouseDragged method consists of the following lawmaking:

                                                                  public void mouseDragged(MouseEvent e) {    if (gobj != cypher) {       gobj.move(due east.getX() - lastX, e.getY() - lastY);       lastX = due east.getX();       lastY = e.getY();    } }                                                            

The if statement simply checks to encounter whether in that location is an object to elevate. If the value of gobj is null , no object is existence dragged, and so the rest of the method is skipped. If an object has been selected by a previous call to mousePressed , the mouseDragged method needs to movement that object by some displacement in each direction. That displacement, however, does not depend on the absolute location of the mouse merely rather in how far it has moved from the bespeak at which you last updated the location of the object. Thus, the arguments to the move method are—for both the ten and y components—the location where the mouse is now minus where it used to exist. Once you accept updated the location of the object being dragged, yous have to tape the mouse coordinates over again then that the location will update correctly on the next mouseDragged phone call.

The concluding listener method specified in Figure 3-vii is mouseClicked , which looks like this:

                                                                  public void mouseClicked(MouseEvent due east) {    if (gobj != zippo) gobj.sendToFront(); }                                                            

The effect of this method is to let the user to move an object to the front by clicking on it, thereby bringing it out from under the other objects on the canvas. The only subtlety in this method is the question of whether information technology is appropriate to rely on the proper initialization of the variable gobj , which holds the electric current object. As it happens, the mouseClicked upshot is always generated in conjunction with a mousePressed and a mouseReleased upshot, both of which precede the mouseClicked event. The gobj variable is therefore fix by mousePressed , just as if you were going to drag it.

3.iii Alternative strategies for blitheness and interactivity (optional)

I of the interesting discoveries that nosotros made during the menstruation of review and comment on the intermediate Coffee Task Force designs was that people pedagogy introductory programming courses take strongly held beliefs about how Java programs should be coded and how those programs should be presented to students. To the extent that our approach differs from the style that someone has grown accustomed to, our designs are often seen as being contrary to the spirit of Java—at least in that person's mind. Unfortunately, those reactions did not point in a single direction considering those strongly held views diverge widely. For example, some people argue that the only appropriate mode to declare a listener method is to employ an anonymous inner form, while others have held that exposing Java'due south listener mechanism at all will be too confusing for students.

From these reactions, it became clear that the Coffee Task Force packages had to back up multiple coding styles and permit private instructors to cull the strategy that seems most closely aligned with their overall pedagogical arroyo. The purpose of this department is to describe several different approaches to animation and interactivity so that you can have a better sense of the range of options. Those alternative strategies are illustrated by recoding two of the example programs presented before in this chapter—the BouncingBall programme from Figure three-ii and the DragObjects program from Figure 3-7—using several dissimilar strategies. The code for each of these version is available on the JTF website.

Although we believe that information technology is important for the Coffee Job Force packages to support a range of coding strategies, information technology is probably non a good idea to try to cover all of these strategies in an introductory class. Many students observe that having multiple strategies to accomplish the aforementioned task is more confusing than liberating. Thus, it is probably all-time to choose a particular approach to animation or consequence handling and then stick with that model until students gain enough feel to appreciate the strengths and weaknesses of the culling styles.

Alternative strategies for implementing animation

The animated applications in section 3.ane use the run divers in the Programme class to bulldoze the animation. The task of dividing the animation into discrete fourth dimension steps is accomplished past making periodic calls to pause . Because the run method runs in a thread of its own, calling interruption does not disable arrangement tasks that run, for example, on Java's upshot-handling thread. The remainder of this section describes two culling animation strategies using the BouncingBall program from Figure 3-2 equally a common point of departure.

The first of these strategies involves giving the ball a thread of its own. The pedagogical foundation for this approach lies in the belief that students of modern programming need to learn about concurrency at a much before phase. Giving the ball its ain thread makes it easy to meet the ball as an active entity in a concurrent world. In this conceptual model, the ball is moving of its own accord rather than being moved by the programme.

I possible implementation of this strategy appears in Figures three-8 and iii-9. Figure 3-viii shows the main program, but all the real work takes place in the RunnableGBall class shown in Figure 3-9, which extends the GBall class. The RunnableGBall class implements Java'southward Runnable interface and then that it can serve as the ground for an independent thread of control. The lawmaking for that run method has the same steps equally in the original implementation:

                                                                  public void run() {    while (true) {       advanceOneTimeStep();       pause(PAUSE_TIME);    } }                                                            

Figure three-viii. Ball bouncing program using a dissever thread

                                          /*  * File: BouncingBallUsingThreads.coffee  * -----------------------------------  * This file implements a unproblematic bouncing ball by creating  * a RunnableBall class and executing it in its own thread.  */                import acm.graphics.*; import acm.programme.*;   public class BouncingBallUsingThreads extends GraphicsProgram {                /** Initialize the brawl and its velocity components */                public void init() {       ball = new RunnableGBall(BALL_RADIUS);       ball.setEnclosureSize(getWidth(), getHeight());       ball.setVelocity(2, one);       add(ball, getWidth() / 2, getHeight() / 2);    }                /** Create a thread to bounce the ball */                public void run() {       waitForClick();       new Thread(ball).first();    }                /* Private constants */                private static final double BALL_RADIUS = ten;                /* Private instance variables */                private RunnableGBall brawl;   }                      

Effigy 3-9. The RunnableGBall class

                                          /*  * File: RunnableGBall.java  * ------------------------  * This file defines an extension to the GBall form that is  * designed to run as a separate thread of command.  */                import acm.graphics.*;   public course RunnableGBall extends GBall implements Runnable {                /** Creates a new ball centered at the origin */                public RunnableGBall(double r) {       super(r);    }                /** Sets the size of the enclosure */                public void setEnclosureSize(double width, double height) {       enclosureWidth = width;       enclosureHeight = superlative;    }                /** Sets the velocity of the ball */                public void setVelocity(double vx, double vy) {       dx = vx;       dy = vy;    }                /** Run forever bouncing the brawl */                public void run() {       while (truthful) {          advanceOneTimeStep();          break(PAUSE_TIME);       }    }                /* Cheque for bounces and accelerate the ball */                individual void advanceOneTimeStep() {       double bx = getX();       double past = getY();       double r = getWidth() / 2;       if (bx < r || bx > enclosureWidth - r) dx = -dx;       if (by < r || past > enclosureHeight - r) dy = -dy;       motility(dx, dy);    }                /* Private constants */                private static final int PAUSE_TIME = 20;                /* Private instance variables */                private double enclosureWidth;    private double enclosureHeight;    private double dx;    private double dy;   }                      

In this case, however, the thread that executes this method is associated with the ball as opposed to being part of the main program. All the BouncingBallUsingThreads plan does on its own behalf is to create the runnable ball, initialize diverse properties such every bit the speed and dimensions of the boundary enclosure, and and then first upwards a divide thread for the brawl by calling

                                                                  new Thread(ball).first();                                                            

At start glance, it would seem that this strategy is better for applications in which at that place is more than one blithe object. Given that whatsoever RunnableBall object can have a thread of its own, information technology would exist simple to create a second ball, add that to the canvas, and kickoff it running as well. As it happens, however, that strategy is difficult to manage considering at that place is no mode to ensure that the balls move at the aforementioned rate. The pause method is only approximate in its timing. Depending on the organisation load, it would be possible for one ball to advance through several fourth dimension steps before the other had a adventure to motility at all. To avoid this problem, information technology is often preferable to have a single animation thread that updates the position of all moving objects during each time step.

The second alternative strategy for animation abandons the idea of pausing a thread altogether. The code for the BouncingBallUsingTimerCode in Figure 3-10 uses Swing's Timer class to alert the main program at regular intervals. When the timer goes off, the plan can advance the ball's position by 1 fourth dimension stride. Although the idea behind this strategy is uncomplicated enough, a couple of aspects of the code are worth noting:

  • The version of the Timer class used here is chosen SwingTimer , which is defined in the acm.util parcel. SwingTimer is a elementary extension of javax.swing.Timer with admittedly no additional features beyond those provided past the base class. The reason for including the SwingTimer class in the JTF package collection is to avoid the unfortunate ambiguity that was introduced into Java in JDK ane.3. At that place are now two publicly attainable classes named Timer , one in javax.swing and the other in coffee.util . If a Java program imports both of these packages, the compiler cannot resolve the identity of the Timer grade unless it is specifically imported from one package or the other. Using the class name SwingTimer eliminates the ambivalence and makes it obvious that the timers in question are of the javax.swing variety.
  • The lawmaking for responding to the events generated by SwingTimer specifies the necessary ActionListener using an anonymous inner class. The definition of both the listener and its response appear in the lines

                                                                                  ActionListener listener = new ActionListener() {    public void actionPerformed(ActionEvent e) {       advanceOneTimeStep();    } };                                                                        

    Using anonymous inner classes to define listeners has become standard in modern Coffee code. Considering the definition of the anonymous listener form is nested within the body of BouncingBallUsingTimer , it has access to the methods and fields defined in the public class, making it possible to invoke advanceOneTimeStep from inside the listener object. At the same time, there is considerable disagreement within the Java education community over when to innovate such classes to new students. Understanding the semantics of inner classes can be difficult for many students. Although information technology is essential to cover this capability eventually, the Task Force felt it was important to support at to the lowest degree some models that enabled instructors to avoid the use of inner classes during the early weeks of an introductory grade.

Figure iii-10. Brawl billowy program using timer events

                                          /*  * File: BouncingBallUsingTimer.java  * ---------------------------------  * This file implements a elementary billowy ball using a Timer to  * implement the blitheness.  */                import acm.graphics.*; import acm.plan.*; import acm.util.*; import java.awt.event.*;   public grade BouncingBallUsingTimer extends GraphicsProgram {                /** Initialize the ball and its velocity components */                public void init() {       ball = new GBall(BALL_RADIUS);       add(ball, getWidth() / 2, getHeight() / two);       dx = 2;       dy = 1;    }                /** Create a timer to accelerate the brawl */                public void run() {       waitForClick();       ActionListener listener = new ActionListener() {          public void actionPerformed(ActionEvent due east) {             advanceOneTimeStep();          }       };       SwingTimer timer = new SwingTimer(TIMER_RATE, listener);       timer.start();    }                /* Bank check for bounces and advance the brawl */                individual void advanceOneTimeStep() {       double bx = brawl.getX();       double past = ball.getY();       if (bx < BALL_RADIUS || bx > getWidth() - BALL_RADIUS) dx = -dx;       if (by < BALL_RADIUS || by > getHeight() - BALL_RADIUS) dy = -dy;       ball.movement(dx, dy);    }                /* Private constants */                private static final double BALL_RADIUS = 10;    private static final int TIMER_RATE = 20;                /* Private case variables */                private GBall ball;    private double dx;    private double dy; }                      

Alternative strategies for responding to mouse events

Just as there is more than one way to implement animation, there are also multiple approaches that one tin take to respond to mouse events. In improver to the strategy of calling the addMouseListeners method to register the program itself as a listener, the Coffee Chore Force packages support several additional coding styles, each of which has its own strengths and weaknesses. The adjacent few paragraphs describe three additional approaches in the context of the DragObjects instance from Figure 3-7

The DragUsingInnerClasses program shown in Figure 3-11 offers the most straightforward rewrite of the original version. The only change is that the mouse listeners are now supplied using anonymous inner classes instead of having the programme itself assume that function. The advantage of this structure is that information technology corresponds well-nigh closely to the style that has become standard in the Java community. The disadvantage is the additional conceptual overhead involved in presenting inner classes to students. In a way, the situation is even more problematic here than it was in the example of the BouncingBallUsingTimer plan presented in the preceding department. In that model, it was possible to use ActionListener as the base grade for the listener, because the one method the interface specifies is defined in the trunk of the inner grade. In the object-dragging case, the base classes need to be MouseAdapter and MouseMotionAdapter to ensure that all the methods in the corresponding interfaces are defined.

The DragUsingGObjectEvents program in Figure 3-12 offers a model that initially seems similar to the original implementation simply that actually represents an important change in betoken of view. In this implementation, the listeners are fastened to the private GObject s and not to the canvas. When a mouse event occurs in the screen expanse of a GObject , the code for the acm.graphics package generates mouse events that use the GObject itself as the source of the upshot and which are so forwarded to whatsoever listeners registered for that object. The advantage here is that the model supports the notion that objects are active entities that tin both generate and accept messages from other objects. The disadvantage lies in the fact that many applications will as well need to assign a listener to the canvass to respond to events that occur outside the context of any of the graphical objects currently existence displayed. If the sail listener is required in any case, it seems easiest to use it for all consequence treatment rather than to prefer two separate models.

The final version of the object-dragging plan appears in Figure three-thirteen. This strategy is derived from the objectdraw package adult at Williams College and uses a simpler model in which the acm.graphics code forwards events to a ready of specialized event handlers divers specifically for this purpose. If a GraphicsProgram subclass defines any of the methods

                                                                  mousePressed(GPoint pt) mouseReleased(GPoint pt) mouseClicked(GPoint pt) mouseMoved(GPoint pt) mouseDragged(GPoint pt)                                                            

and so that method is called whenever the appropriate result occurs in the GCanvas . The parameter pt in each of these methods is the signal at which the mouse event occurred, already translated into the real-valued coordinate space of the acm.graphics package. This model completely hides the details of mouse events and mouse listeners, so that the student demand not, for example, import the coffee.awt.issue package or accept whatever special steps to annals the plan as a listener. All of that comes for free. The primary disadvantage is that students who learn this strategy for event handling will have to learn how standard Java listeners work at some later on point.

Figure three-11. Object-dragging program using inner classes to specify the listeners

                                          /*  * File: DragUsingInnerClasses.java  * --------------------------------  * This implementation illustrates the technique of defining  * listeners as bearding inner classes.  */                import java.awt.*; import java.awt.event.*; import acm.graphics.*; import acm.program.*;                /** This class displays a mouse-draggable rectangle and oval */                public class DragUsingInnerClasses extends GraphicsProgram {                /** Initializes the plan */                public void init() {       GRect rect = new GRect(100, 100, 150, 100);       rect.setFilled(true);       rect.setColor(Color.RED);       add(rect);       GOval oval = new GOval(300, 115, 100, lxx);       oval.setFilled(true);       oval.setColor(Color.GREEN);       add together(oval);       GCanvas canvas = getGCanvas();       canvas.addMouseListener(new MouseAdapter() {          public void mousePressed(MouseEvent e) {             last = new GPoint(e.getPoint());             gobj = getElementAt(last);          }           public void mouseClicked(MouseEvent e) {             if (gobj != nothing) gobj.sendToFront();          }       });       sheet.addMouseMotionListener(new MouseMotionAdapter() {          public void mouseDragged(MouseEvent e) {             if (gobj != null) {                gobj.move(east.getX() - last.getX(),                          eastward.getY() - last.getY());                terminal = new GPoint(e.getPoint());             }          }       });    }                /* Private example variables */                private GObject gobj;                /* The object being dragged */                private GPoint final;                /* The terminal mouse position  */                }                      

Effigy iii-12. Object-dragging program that listens to the GObjects

                                          /*  * File: DragUsingGObjectEvents.java  * ---------------------------------  * This implementation illustrates the technique of assigning  * listeners to GObjects.  */                import coffee.awt.*; import java.awt.event.*; import acm.graphics.*; import acm.program.*;                /** This class displays a mouse-draggable rectangle and oval */                public grade DragUsingGObjectEvents extends GraphicsProgram {                /** Initializes the program */                public void init() {       GRect rect = new GRect(100, 100, 150, 100);       rect.setFilled(true);       rect.setColor(Color.RED);       rect.addMouseListener(this);       rect.addMouseMotionListener(this);       add(rect);       GOval oval = new GOval(300, 115, 100, lxx);       oval.setFilled(truthful);       oval.setColor(Color.Dark-green);       oval.addMouseListener(this);       oval.addMouseMotionListener(this);       add(oval);    }                /** Called on mouse press to record the coordinates of the click */                public void mousePressed(MouseEvent eastward) {       last = new GPoint(e.getPoint());    }                /** Chosen on mouse drag to reposition the object */                public void mouseDragged(MouseEvent e) {       GObject gobj = (GObject) e.getSource();       gobj.move(eastward.getX() - concluding.getX(), due east.getY() - concluding.getY());       terminal = new GPoint(e.getPoint());    }                /** Called on mouse click to move this object to the front */                public void mouseClicked(MouseEvent e) {       GObject gobj = (GObject) e.getSource();       gobj.sendToFront();    }                /* Private example variables */                private GPoint last;                /* The last mouse position */                }                      

Effigy 3-13. Object-dragging program using callback methods in the manner of objectdraw

                                          /*  * File: DragUsingObjectDrawModel.java  * -----------------------------------  * This implementation illustrates the technique of using callback  * methods in the way of the objectdraw package.  */                import coffee.awt.*; import acm.graphics.*; import acm.program.*;                /** This course displays a mouse-draggable rectangle and oval */                public class DragUsingObjectDrawModel extends GraphicsProgram {                /** Initializes the program */                public void init() {       GRect rect = new GRect(100, 100, 150, 100);       rect.setFilled(true);       rect.setColor(Color.Cherry);       add(rect);       GOval oval = new GOval(300, 115, 100, seventy);       oval.setFilled(true);       oval.setColor(Colour.GREEN);       add together(oval);    }                /** Called on mouse press to record the coordinates of the click */                public void mousePressed(GPoint pt) {       last = pt;       gobj = getElementAt(last);    }                /** Called on mouse drag to reposition the object */                public void mouseDragged(GPoint pt) {       if (gobj != zero) {          gobj.move(pt.getX() - last.getX(), pt.getY() - concluding.getY());          last = pt;       }    }                /** Chosen on mouse click to move this object to the front */                public void mouseClicked(GPoint pt) {       if (gobj != zero) gobj.sendToFront();    }                /* Individual instance variables */                private GObject gobj;                /* The object beingness dragged */                private GPoint final;                /* The final mouse position  */                }                      


How To Register Mousepressed Events Only On Part Of The Canvas,

Source: https://cs.stanford.edu/people/eroberts//jtf/tutorial/AnimationAndInteractivity.html

Posted by: holtonphrebre1964.blogspot.com

0 Response to "How To Register Mousepressed Events Only On Part Of The Canvas"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel