DrawingCanvas

The DrawingCanvas interface describes the canvas on which objects are placed. In addition to being needed as a parameter when you create an object, the canvas() has several methods that make it useful in its own right: it has methods that allow you to get its width and height, set the background color, ask it to clear the canvas, or zoom in on one part of the canvas. It also provides a way to retrieve a list of all the objects on the canvas, so that you can search through that list and do something to each object.

1. The basics: size, background, clearing

Suppose that you are trying to create an object that will be centered on the screen. If you know that the screen is 200 pixels wide, then it is clear that the object should be at x = 100. But unfortunately, the size of an applet can change depending on where it is being used. You need some way to find out how wide the screen is, so that you can create objects sized in proportion to it.

public int getWidth()
public int getHeight()

Here is some code that uses these method to create some Text centered in the top half of the screen, and a FramedOval that nearly fills the screen, with an inset of 10 on each side:

Text text = new Text("Hello World!", canvas.getWidth() / 2, canvas.getHeight() / 4, canvas);
text.setAlignment(Text.CENTER, Text.CENTER);

FramedOval oval = new FramedOval(10, 10, canvas.getWidth() - 20, canvas.getHeight() - 20, canvas);

The canvas also allows you to get and set the background color, in case you want it to be something other than white. The color ought to be fully opaque; anything transparent would lead to weird results (like having a "ghost" of whatever was previously on the screen stay on the screen).

public void setBackground(Color color)
public Color getBackground()

Finally, the canvas has a method to clear all objects from the canvas. This is equivalent to calling the removeFromCanvas() method of each object in turn.

public void clear()

Clearing can be a simple way to implement something that looks like dragging an object, if you have only one object on the canvas:

public void onMouseDrag(Location point) {
   canvas.clear();
   new FilledOval(point, 20, 20, canvas);
}

2. The loupe: zooming in on a part of the canvas

Your browser doesn't do Java.
TreasureHunt.java
Your browser doesn't do Java.
MazeRunner.java
LoupeMaze.java
Sometimes when you have made a particularly nice-looking program, you want to be able to zoom in on a part of it to admire your work in more detail. Or, while debugging you may want to be able to zoom in to check alignment. Or, perhaps you have really small text over which you want a magnifying glass to pan, perhaps as the opening credits to your game.

For all these things, you can use the "loupe" feature of the canvas. "Loupe" is just a fancy word for a magnifying glass, of the sort used by jewelers and other people who need to look at very small objects.

The loupe is set by giving the canvas a point on the screen to center on, the diameter of the area to magnify, and a factor to zoom by:

public void setLoupe(Location point, double diameter, double zoom)
public void setLoupe(Location point)

The area to be zoomed in on is centered at the point you give, with the diameter you specified. It will be zoomed by the zoom factor, so the actual size on screen that the loupe will seem to be is diameter * zoom. If I zoom a diameter of 30 by a factor of 4, I seem a circle that appears 120 pixels wide, but contains only what would normally appear in 30 pixels.

If you set the loupe with just a position, it will automatically use the most recently used diameter and zoom, or a diameter of 30 and a zoom of 3 if this canvas has never had its loupe set before.

Once you want the loupe to disappear, class clearLoupe():

public void clearLoupe()

A very typical thing to do is to have the loupe appear when you click, drag with the mouse, and disappear when the mouse is released:

public void onMousePress(Location point) {
   canvas.setLoupe(point, 30, 3);
}

public void onMouseDrag(Location point) {
   canvas.setLoupe(point);
}

public void onMouseRelease(Location point) {
   canvas.clearLoupe();
}

It is also possible to use the loupe for much more complex things. The maze example to the right is a large, unmoving maze with the loupe following the ball around so that the maze appears to shift and keep the ball in the middle.

3. Getting a list of objects on the canvas

Your browser doesn't do Java.
DragDrawables.java
The canvas keeps a list of all the objects that currently exist on it. The method getDrawableIterator returns an object that will go through these and return them to you one by one, making it easy to search through all the objects on the canvas:

public DrawableIterator getDrawableIterator()

A DrawableIterator is just an easy way to deal with the list of objects. It has only two methods that you need to worry about: the hasNext() methods reports whether there are any more objects left to look at, and the next() method returns the next object:

public boolean hasNext()
public DrawableInterface next()

The next() method will return a new object every time it is called; it automatically advances through the list. Typically, you will have a loop repeating as long as hasNext() returns true, and each time through the loop, get the next item and do something with it.

DrawableIterator iterator = canvas.getDrawableIterator();
while(iteartor.hasNext()) {
   DrawableInterface draw = iterator.next();
   // Do something with "draw", like:
   
   // Find any object containing a point:
   if(draw.contains(point)) {
      ...
   }
   
   // Move every object on the screen:
   draw.move(20, 20);
   
   // etc.
   ...
}

A DrawableIterator will return only objects that were on the screen when it was created, in the order that they were in when it was created. So, if you change the draw order or add objects while you are going through the iterator, you won't see the new objects or see that objects have changed place until you make a new iterator. This helps to avoid situations that might cause infinite looping.