Session 1: Objects and Events

1. Running a program

Create a Java program that will draw objects on the screen in response to mouse and keyboard events.
  1. Running a program
  2. Creating objects
  3. Object creation practice
  4. Compound objects
  5. Mouse and keyboard events
In this seminar we will be using the computer language Java to write computer programs. We will use a program called Eclipse to edit our programs with. You may already be familiar with Eclipse and Java, but if you are not, that is not a problem; I will explain what you need to know as we go along.

The files you need for this seminar are all in this zip file. Download it and extract it to wherever you want to keep your files:

NetworkingSeminar.zip

Now, run Eclipse. If it asks you to choose a workspace, choose the "workspace" directory inside the directory you just unzipped. If you already have Eclipse set up to open your own workspace by default, switch to this one by using the "Switch workspace" option in the File menu.

(If you prefer to use an IDE other than Eclipse, you can instead download NetworkingSeminarFiles.zip, which contains the same files but not the extra information needed to make them into an eclipse workspace. You will then have to figure out how to get those projects, and the libraries they use, imported into your IDE.)

A program called HelloObjectDraw should be open in the editor in the main part of the window. To run this program, click on the "run" button in the toolbar. You should see a window appear with a few rectangles and ovals drawn in it.

2. Creating objects

The shapes you see were drawn by these instructions in the program you just saw:

new FramedRect(10, 20, 220, 170, canvas);
new FilledRect(30, 210, 60, 160, canvas);
new FilledOval(280, 50, 90, 90, canvas);
new FramedOval(180, 200, 210, 150, canvas);

All of these are "object creation" instructions, and they all have the same basic anatomy:Try changing the class of one of the objects, or try changing its width and height to something else, then run the program again to see what changed. You can run as many copies of your program as you like; actually, what the program file is doing is defining a class, objects of which can be made with new.

In one of the running copies of the program, turn on the grid and the rulers in the "View" menu. You will notice that the coordinate system is a little bit strange: (0, 0) is at the top left, and the y coordinate increases as you go down the screen, rather than up as in math. The (x, y) parameters of each object specify where the top left corner is.

You can use this grid to help you figure out how to solve our first exercise. I have given three options here to try to challenge all levels of programmers.

Beginner programmers:
Try to change the program so that it draws something resembling this. You don't have to exactly match the drawing; just try to get the same types of shapes in roughly the same relation to each other.
Give me a hint?
There are five objects here, so the first thing I would do is to copy and paste one of the object creation instructions in my program so that there are five of them. Then, I would change their classes to match what I see in the picture. Finally, I would go through one by one and try to figure out the (x, y) of the top left corner, the width, and the height.
OK, just tell me.
The code I used to draw these objects was:

new FilledRect(20, 20, 220, 100, canvas);
new FramedOval(260, 20, 120, 360, canvas);
new FramedOval(20, 140, 80, 240, canvas);
new FramedRect(120, 140, 120, 120, canvas);
new FilledOval(120, 280, 120, 100, canvas);

You could create the objects in any order, and your numbers are probably somewhat different from mine.


Experienced programmers:
Use loops to create the pattern shown here. The ovals are all 20 by 20, and 20 pixels from the edge. The rectangles are 20 tall, 20 pixels apart, start at y = 60, and have a width equal to their y coordinate.
Give me a hint?
There will be two separate loops in this program. For the ovals, you will just want a loop that counts up a variable from 20 to 360 by 20, creating an oval at that x coordinate each time through the loop. For the rectangles, the fact that the y and the width are equal means that I can count up just one variable to use for each; it will start at 60 and count up to 340 in steps of 40.
OK, just tell me.
The code that I used to draw this image was:

int x = 20;
while(x <= 360) {
    new FilledOval(x, 20, 20, 20, canvas);
    x = x + 20;
}

int y = 60;
while(y <= 340) {
    new FramedRect(20, y, y, 20, canvas);
    y = y + 40;
}

The first loop sets x to 20, then repeats until x reaches 360, creating a FilledOval and then adding 20 to x each time. The second loop does a similar thing, except that I used the current value of y as both the y coordinate and the width when creating the FramedRect.


Expert programmers:
Try creating the pattern shown here. The ovals and rectangles are all 20 by 20.
Give me a hint?
When looping over a two dimensional grid, normally you will have one loop counting up through the x values, with another loop inside it looping over all the y values for each value of x. Then, inside the inner loop, you have to decide whether to draw an oval or a rectangle. Perhaps it would help if I pointed out that for all the rectangles, the x and y coordinates add up to a multiple of 40.
OK, just tell me.
The code I used to draw this image was:

for(int x = 20; x < 380; x += 20) {
    for(int y = 20; y < 380; y += 20) {
        if((x + y) % 40 == 0) {
            new FilledRect(x, y, 20, 20, canvas);
        } else {
            new FilledOval(x, y, 20, 20, canvas);
        }
    }
}

So, the program counts through all the possible values of x, and in each column it then counts through all the values of y. If the sum of the two has a remainder of zero when dividing by forty, a rectangle is drawn there; otherwise, an oval is drawn.

3. Object creation practice

At this point, it is worth investing some time in getting really comfortable with how to make these particular objects, since they will be the building blocks of everything else we do. If you don't have to stop and think about how to create a particular shape, you can allocate more mental resources to a larger understanding of your programs. We will be playing a short game in partners to help you get comfortable making objects before we move on.

In the file list at the right side of your Eclipse window, double-click "S1-ObjectsAndEvents", then "(default package)", then "ObjectCreationModel.java". A new program will appear in the editor, looking very similar to HellowObjectDraw. Click the "run" button. The window that appears has five shapes in it. This is the model you will try to write code to match.

Now, open the program "ObjectCreationGame.java", and run it. If you put the two program windows side by side, you will see that, so far, the ObjectCreationGame program creates two of the shapes that appear in the model. If you click in the ObjectCreationGame window, it will test the shapes it has, circling the two that are correct in green and displaying the missing ones with flashing red outlines.

Your job is to try to add instructions in ObjectCreationGame to make it draw objects that exactly match those in ObjectCreationModel. When you run the program and click in the window, it will show you which of your shapes are correct (circled in green), which of your shapes are wrong (circled in blue) and which of the shapes in the model are missing (circled in red).

Working with a partner sitting next to you, run ObjectCreationModel on one computer, and then work together to figure out the code to duplicate it in ObjectCreationGame on the other computer. To makes things easier, I made all the shape edges line up on multiples of ten. If you complete this challenge, change the number "1000" in both the model and the game to something different (between 1000 and 1999) to get a different pattern to match, and switch which partner is typing in code.

The next level of this game introduces color. Enter a number between 2000 and 2999 in the model and run it. You will see the same sorts of shapes, but in different colors.

How did those different colors get there? The objects are still the same kind of shape - a filled oval, a framed rectangle, and so on - so the class of object must not have changed. The only possibility, then, is that there is a new parameter that sets the color to something other than black. This parameter comes just before canvas:

new FilledRect(10, 20, 100, 80, Color.RED, canvas);

"Color.RED" is how you say "the color red" in Java. The colors you will need for this exercise are RED, GREEN, BLUE, YELLOW, CYAN, MAGENTA, GRAY, and BLACK. We will learn very soon how to create other colors that aren't on that list.

After you try out a round or two with color, the next thing we can do is to introduce more shapes. The one other shape that you will definitely find useful is a Line:

new Line(10, 20, 60, 150, Color.BLUE, canvas);

This instruction creates a line segment going from (10, 20) to (60, 150). Notice that the parameters now are the coordinates of the end points; width and height aren't parameters that would make sense for a line.

If you increase the test number to something between 3000 and 3999, the game will add lines in to the mix. Play a few rounds to practice. If you feel like you really get it and want to try all the possible shapes, you can pump tat number up to 5000 or more. Here is a reference for the other parameters for these shapes. In this game, arc width and height are chosen in multiples of 20, and start angle and arc angle in multiples of 30.

4. Compound objects

The parameters I use to create an object need not be only numbers - I can actually pass an entire object as a parameter. For example, there is a class of object called Location that could take the place of the (x, y) parameters. These two instructions do the same thing:

new Line(10, 20, 60, 150, canvas);
new Line(new Location(10, 20), new Location(60, 150), canvas);

The second form of the instruction has a few advantages. For example, it makes it clear that the line is connecting two points. With just four numbers there, you might wonder if the second two are width and height, or if the order is (x1, x2, y1, y2).

You can find out what the possible sets of parameters are, when creating an object, by pressing control-space when the cursor is just after the "(". This will tell you not only the type of parameter, but a short name describing what it is for. You will notice that number parameters show up with the type double.

So, for example, one possibility for creating a FilledRect requires just two Location objects - any two opposite corners - and then a Color object and the canvas. You should be able to see why this is useful - it's a lot simpler to locate two corners of an oval than to subtract to find out the width and height.

You can also create and pass along a Color object for the color parameter. Colors are made by mixing some amount of red, green, and blue, each an integer from 0 to 255. So, for example, this code would make a FilledRect with one corner at (20, 220), one at (300, 10), colored purple:

new FilledRect(new Location(20, 220), new Location(300, 10), new Color(100, 0, 150), canvas);

Try out another round of the object creation game, and this time, try to use no bare numbers, just Location objects. Practice with creating objects in this way will be very useful when we start responding to mouse events and so we have a Location of the mouse handy to be used.

Optional exercise: Making Lego people
Everyone knows that you can detach the legs and head from a Lego person and attach different ones in their place. But not everyone realizes that it is also possible to swap the arms, hands, and individual legs.

Open up and run the program "CompoundObjectPractice.java." You will see a lego person appear somewhere on the screen. As you can see in the program code, this person is a big, complex, compound object. The main object is a Body, but in order to create it, I had to pass along a Head, a Legs, and two Arms as parameters. Some of these objects required me to make still more objects; for example, making a Legs requires me to pass along two Leg objects.

The smaller objects can stand on their own, if I add them to the canvas. So, for example, I could make just a set of Legs like this:

new Legs(
    new Leg(),
    new Leg(),
    canvas);

Each of the objects allows me to set its color by passing a Color as the last parameter (still before canvas, if it exists). So, this would make a blue Arm with a gray Hand:

new Arm(
    new Hand(Color.GRAY),
    Color.BLUE,
    canvas);

It is also possible to pass null as one of the parts to mean that that part doesn't exist. So, the code below would make a Body with just a head. (Check your understanding: What color is the head? The body?)

new Body(
    new Head(Color.RED),
    Color.BLUE,
    canvas);

Try to create as many as you can of the lego people shown in this picture.
Give me a hint?
One technique that often works for me is to start out just writing the instruction to construct the outermost object, passing null for all the parameters except the color and the canvas. I can then run it and make sure that works so far. Then I go back to those null parameters and decide which need to be replaced with an object.

It is a lot easier to see what you are doing if you follow the pattern that I have in my code and put each parameter on its own line, indenting the parameters of each object one more than the object it is enclosed in. Then I can easily see which parameters belong to which object.

Keeping commas and parentheses in the right places, and keeping the parameters in the right order, are the two most frustrating things about this assignment. These things are hard for all beginning programmers - don't be discouraged! Remember that you can use control-space to get a list of the parameters in order.
OK, just tell me.
The code below creates the objects in the image are listed in "reading order" - that is, starting from the top left and going left to the end of the first line, then continuing with the line below.

new Hand(
    Color.GRAY,
    canvas);

new Arm(
    new Hand(Color.BLUE),
    Color.GREEN,
    canvas);

new Legs(
    new Leg(Color.BLUE),
    new Leg(Color.GREEN),
    Color.CYAN,
    canvas);

new Arm(
    null,
    Color.YELLOW,
    canvas);

new Legs(
    new Leg(Color.RED),
    null,
    Color.MAGENTA,
    canvas);

new Body(
    new Head(Color.GRAY),
    null,
    new Arm(
        new Hand(Color.YELLOW),
        Color.BLUE),
    null,
    Color.YELLOW,
    canvas);

new Body(
    null,
    new Legs(
        null,
        new Leg(Color.GRAY),
        Color.BLACK),
    new Arm(
        null,
        Color.CYAN),
    null,
    Color.RED,
    canvas);

new Body(
    new Head(Color.GREEN),
    new Legs(
        new Leg(Color.CYAN),
        new Leg(Color.CYAN),
        Color.BLUE),
    new Arm(
        new Hand(Color.YELLOW),
        Color.RED),
    new Arm(
        new Hand(Color.BLACK),
        Color.GRAY),
    Color.MAGENTA,
    canvas);

5. Mouse and keyboard events

You have already seen one example of responding to mouse input - the ObjectCreationTest program tests your objects when you press the mouse button. How does it do this?

At this point, we need to take a moment to talk about how a program file is organized. Rather than having one long string of instructions to run all at once, it is broken down into pieces, called blocks, each describing a particular part of the program. To show what belongs to what block, we do two things: we surround the contents of the block with {} "curly braces", and we indent the contents of the block one tab more than the block it is in.

Class {
    MethodA {
        Instruction1;
        Instruction2;
    }
    
    MethodB {
        Instruction3;
    }
    
    MethodC {
        Instruction4;
        Instruction5;
        Instruction6;
    }
}

So, in the outline above, Instruction5 is inside a block called MethodC, which is inside a block called Class. There are no instructions inside the Class block, there are just more blocks, the Methods.

The names of the blocks are a bit more complicated in a real program, but, looking at a program like ObjectCreationGame in this way, we can see that the instruction "new ObjectCreationGame()" is inside a block called "public static void main(String[] args", which in turn is inside a block called "public class ObjectCreationGame extends FrameWindowController".

All of the programs you ever write in Java will have this same basic structure. The outermost block contains the whole definition of a new class of object you are designing. Inside that block are method blocks. A "method" is the set of instructions that a program will run in response to a particular thing happening. ObjectCreationGame has three methods:
(Methods are commonly referred to just by their name, which appears before the "(". So, rather than saying "public void onMousePress(Location point)" to refer to that block, I can just abbreviate that to "onMousePress()". Similarly, a class is referred to as just "ObjectCreationGame" rather than "public class ObjectCreationGame extends FrameWindowController". The whole "signature" of the block provides important information about the class or method, but the only really unique part is the name.)

Suppose that I wanted to write a program that would draw something when the mouse is pressed, then hide it when the mouse is released. My program would have to have an onMousePress() method, plus another one, which, as you can probably guess, is called onMouseRelease(). I would put an instruction in the onMousePress() method to create an object, and one in onMouseRelease() to clear the canvas:

public class MouseEventResponder extends FrameWindowController {
    public void onMousePress(Location point) {
        new FilledRect(50, 50, 300, 300, canvas);
    }
    
    public void onMouseRelease(Location point) {
        canvas.clear();
    }
    
    public static void main(String[] args) {
        new MouseEventResponder();
    }
}

When adding a method to your program, it is very important to get the "signature" exactly correct. If I had called the second method "onMouseReleased", it wouldn't ever be run. Eclipse helps you out by drawing a little green triangle next to a method it recognizes as matching one of the commonly used ones. The mouse events all have a similar-looking signature; the ones you haven't seen yet are called onMouseEnter(), onMouseExit(), onMouseMove(), and onMouseDrag().

We have two quick exercises to do before finishing this session. Feel free to work alone or with a partner as you prefer. The first one uses mouse events; the second will introduce you to keyboard events.

Your first mouse event exercise:
Modify the program MouseEventResponder, which you can find in Eclipse. When it first runs, an oval should appear on the screen. Pressing the mouse should cause the oval to be replaced by a rectangle; releasing the mouse should cause the rectangle to be replaced by an oval again.
Give me a hint?
First of all, when you read a problem like this, you should note that your program needs to do things "when it first runs", "when the mouse is pressed", and "when the mouse is released." So, you will need three methods: begin(), onMousePress(), and onMouseRelease(). Look for the green triangle to ensure you got the method signatures right.

The tricky part here is how to make one object be replaced by another. Notice that really all that means is that you clear the canvas and then create another object.
OK, just tell me.
This program will do as the exercise asked:

public class MouseEventResponder extends FrameWindowController {
    public void begin() {
        new FilledOval(50, 50, 300, 300, canvas);
    }
    
    public void onMousePress(Location point) {
        canvas.clear();
        new FilledRect(50, 50, 300, 300, canvas);
    }
    
    public void onMouseRelease(Location point) {
        canvas.clear();
        new FilledOval(50, 50, 300, 300, canvas);
    }
    
    public static void main(String[] args) {
        new MouseEventResponder();
    }
}


Your first keyboard event exercise:
Keyboard events can be handled in the same way as mouse events. Open up and run the program KeyEventResponder in Eclipse. It responds to pressing and releasing the space bar. Notice that the method signatures for this are similar to the mouse ones, but without the "Location point" part.

Change this program so that when the "r", "g", or "b" keys is pressed, a red, green, or blue shape, respectively, appears on the window. Pressing the space bar should clear the window. The method you will need are called onRPress(), onBPress(), and onGPress().
Give me a hint?
The basic skeleton of your program, with the methods defined but no instructions filled in, would look like this:

public class KeyEventResponder extends FrameWindowController {
    public void onRPress() {
        
    }
    
    public void onGPress() {
        
    }
    
    public void onBPress() {
        
    }
    
    public void onSpacePress() {
        
    }
    
    public static void main(String[] args) {
        new KeyEventResponder();
    }
}

You could simply copy this into Eclipse. You might want to then fix up the indentation by selecting the whole file (control-A) and then pressing control-I.
OK, just tell me.
Here is a program that meets the requirements of the assignment:

public class KeyEventResponder extends FrameWindowController {
    public void onRPress() {
        new FilledOval(20, 20, 240, 160, Color.RED, canvas);
    }
    
    public void onGPress() {
        new FilledOval(280, 20, 100, 360, Color.GREEN, canvas);
    }
    
    public void onBPress() {
        new FilledRect(80, 200, 180, 180, Color.BLUE, canvas);
    }
    
    public void onSpacePress() {
        canvas.clear();
    }
    
    public static void main(String[] args) {
        new KeyEventResponder();
    }
}

Of course, the particular shapes you create could differ from mine, as long as they are the right colors.


You now know how to make a Java program that will draw things in a window and respond to the user's actions with the mouse and keyboard. In the next session, we will learn how to account for where in particular a mouse event happened, and we will learn to keep track of multiple shapes in the window and manipulate them in response to events.

back to Creating Network Games with ObjectDraw