Next, we need to set up the graphics. Before we jump headfirst into Java's drawing functions, we need to think about how we're going to store the user's drawing.
We could create an array of arrays of points to store each "stroke." (Confusing? Explanation: The first array is the array of "strokes." The second array stores the points that make up each stroke.)
I'm going to take the easy way out here. That is, we'll create a drawing bufferan off-screen image. We can use Java's drawing functions to draw right into the buffer. Then, when we need to, we copy the entire buffer back to the screen. This takes care of the storage problemwe let Java do thatand also speeds up the display somewhat. (You computer-graphics people may recognize this as double buffering.)
All right, enough talk. Let's start coding. Open PaintApp.java and add the lines marked in blue:
import java.awt.*; import java.applet.*; // // PaintApp // public class PaintApp extends Applet { // // Fields // private Dimension size; private Image drawImage; private Graphics gDraw; // // Operations // public void init() { size = size(); clearImage(); } private void clearImage() { drawImage = createImage(size.width, size.height); gDraw = drawImage.getGraphics(); } }
Don't compile the applet yet. We haven't enabled any user interaction, so the applet will still look the same.
PaintApp
in DetailHere's your first look at Java fields, which are the data members of a class. In the section marked Fields, we define three of them: size
, drawImage
, and gDraw
. Note the syntax:
[access-modifier] data-type identifier;
Because the access modifier for all three cases is private
, code outside the PaintApp class can't get to them. It's generally a good idea to "hide" fieldsit can prevent unintentional coding errors. This idea is called data encapsulation.
Our first field is size
, which we declare an object of class Dimension
:
private Dimension size;
A Dimension
object has two fields, height
and width
. We'll be using size
to store the size of our applet.
Our second field is drawImage
, which is an Image
object. This will be our drawing buffer. An Image
doesn't let us draw on it directly though. Instead, we need to get a Graphics
object that's linked to it. That's the purpose of the last field, gDraw
. The Graphics
class, as its name implies, contains all the drawing routines that we'll be using.
After the Fields section comes Operations, which contains the class's methods. Remember that methods are the procedures and functions that belong to a class. We have two methods, init()
and clearImage()
.
Here's the syntax of a method:
[access-modifier] return-data-type identifier([arguments]) { body-statements; }
The access modifier, like that for an field, determines whether the method is visible outside the class. The first method, init()
, is declared public
, because this method is called by Java whenever the applet starts. If we declared it private
, Java wouldn't be able to find it. Our second method though, clearImage(), is private
. This is a "helper function" that our class uses internally, so there's no need for outside code to use it and possibly screw things up.
The data type of a method tells Java that the method is a function and is going to return the results of some calculation. If you don't want to return anything, use the special void
data type. This makes the method a plain procedure. Both the methods return void
, or nothing.
The stuff inside the parentheses after the identifier (the name of the method) lists the arguments that the method takes. Arguments are additional data that are passed to the method. Neither of our methods need any additional data, so there's nothing between the parentheses. (Note to C programmers: don't use void
if a method takes no arguments.)
Finally comes the method body, inside the omnipresent curly braces. The body contains all the statements to be executed when the method is called. Each statement is terminated by a semicolon (;). If the method is a function, be sure there is a return
statement at the end (more on this later).
The init()
method is called whenever an applet starts. You should place one-time initialization code inside this method. In PaintApp
, init()
is defined as follows:
public void init() { size = size(); clearImage(); }
The first statement gets the size of the applet by calling the Applet
class's size()
function. This is then assigned to our size
field. (Actually, we could simply call size()
whenever we wanted the applet size, but saving it to a variable optimizes things a bit.)
The second statement calls our clearImage()
method, defined as follows:
private void clearImage() { drawImage = createImage(size.width, size.height); gDraw = drawImage.getGraphics(); }
You create an image by calling createImage()
, passing it the width and height of the image you want to create. In this case, we want an image that's the same size as the applet. The new image is assigned to the drawImage
field.
In order to draw anything on an Image
, though, you need to get a Graphics
object that's linked to it. The second statement does that, by calling the getGraphics()
method of drawImage
to retrieve the Graphics
object, and then storing it in gDraw
.
In the next step, we'll complete our graphics setup.