SUNY Geneseo Department of Computer Science


Lab 1 -- Java Review

CSci 240, Spring 2007

Prof. Doug Baldwin

Due Tuesday, January 23

Purpose

The purpose of this lab is to help you remember programming techniques and Java features that are likely to be used in this course, and to give me a sense for which of those techniques and features I should review during the course. This exercise also helps you get acquainted with the programming environment you will be using, if you aren't already familiar with it.

Background

In order to do this exercise, you will need to know how to use some Java programming environment, and you will need to know the basics of graphics in Java.

Programming Environments

I will walk through setting up, editing, and running a Java program with XCode during the lab session for anyone who is interested. If you prefer to use some other programming environment, you are welcome to do so, although you will be more on your own to learn how to use that environment.

Simple Java Graphics

The ultimate product in this exercise is a program that draws a certain pattern in a window. You will therefore need to know something about windows and graphics in Java to write this program. You can read about the various graphics classes in detail in the Java library documentation, but the following is a summary of what you should need for this exercise.

Coordinates

Computer graphics is generally a matter of making the computer draw lines, rectangles, and similar shapes in a window on the monitor. You describe these shapes relative to a two-dimensional coordinate system -- for example, to draw a line you would say where its endpoints are in this coordinate system, and the computer would then draw the line between those points.

Coordinates are measured in units of pixels, where a pixel is the smallest point on the screen that can be colored. A typical monitor today is on the order of 1000 pixels wide and high, while typical windows are several hundred pixels wide and high. Coordinate values are always integers.

In every window coordinate system I have ever seen, one axis runs horizontally across the window, and the other runs vertically down the window. Coordinates on the horizontal axis run from 0 at the left edge of a window to the window's width in pixels, minus one, on the right. Vertical coordinates run from 0 at the top to the window's height minus one at the bottom. Note that vertical coordinates increase down, contrary to coordinate systems you are used to from mathematics; point (0,0) is the upper left corner of the window.

Windows

The Java library class JFrame represents a window on your monitor.

JFrame is defined in the javax.swing package, so before you do anything with a JFrame you need to import that package. If you want to change how the window behaves when closed (via the setDefaultCloseOperation message, described below), you will also need to import the WindowConstants interface. Thus, statements such as

    import javax.swing.JFrame;
    import javax.swing.WindowConstants;

should appear near the beginning of any file that contains code that uses JFrame.

JFrame has a constructor that takes the window's title (a string) as its only parameter. For example

    JFrame window = new JFrame( "A Sample Window" );

This constructor (and all other JFrame constructors) create JFrame objects with a default size, which is not necessarily the size you will want (it's often very small). To change a JFrame object's size, send it a setSize message, with the desired width as the first parameter and the desired height as the second parameter. Width and height are measured in pixels. For example, to resize JFrame window to be 500 pixels wide by 200 high, use the statement

    window.setSize( 500, 200 );  

The JFrame constructors initialize windows so that they are not visible. This allows you to size and otherwise adjust a JFrame to look the way you want it to before it appears as a window on the screen, but sooner or later you will need to make the window visible. To do this, send the window a setVisible message with parameter true. For example...

    window.setVisible( true );  

By default, closing a JFrame makes the window disappear but doesn't do anything else. To change this behavior, send the JFrame a setDefaultCloseOperation message. This message technically takes an integer that encodes the action to take when the window closes as its parameter. Fortunately, programmers needn't know what integers stand for what actions, because a set of predefined constants stores the possible values. These constants are part of the Java library's WindowConstants interface. One particularly popular one is EXIT_ON_CLOSE, which indicates that the program that created a window should exit when that window is closed. For example, a program that wanted to exit when JFrame window closed would contain the statement

    window.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );

in the code that sets up the window.

Canvases

If you want to draw a picture in a JFrame, you need to put an object that can display the picture into the JFrame -- JFrame objects cannot display pictures (or much of anything else) by themselves. The Java library provides a class named Canvas for just this purpose. A Canvas is basically a region that contains some drawing in a window. The most important message that Canvas objects handle is paint, which causes a Canvas to draw its drawing. This way of drawing the drawing implies that each drawing corresponds to a different kind of Canvas, since each drawing is produced by different code in the paint method. Thus, in order to draw a drawing of your own design, you need to define a subclass of Canvas with a paint method that draws your drawing.

Note that paint messages are sent to Canvas objects automatically, by the Java runtime system, when the runtime system thinks the contents of the Canvas need to be (re)drawn -- for example, when the JFrame containing the Canvas becomes visible, when it is resized, etc. Therefore you will never write a statement that sends a paint message.

The Canvas class is defined in the java.awt package, so before you can define a subclass of Canvas, you need to import Canvas from that package. In order to write a paint method for the subclass you will also need to import the Graphics class from java.awt. Statements such as

    import java.awt.Canvas;
    import java.awt.Graphics;

should therefore appear near the beginning of any file that defines a subclass of Canvas.

Here is an example of a complete but minimal subclass of Canvas. This subclass represents pictures consisting of a single flat line. Note that the paint method receives a Graphics object as its parameter. This object is what actually does graphics operations; the Graphics class is described in the next section of this handout.

    import java.awt.Canvas;
    import java.awt.Graphics;

    class SimpleCanvas extends Canvas {
     
        public void paint( Graphics g ) {
            g.drawLine( 10, 10, 100, 10 );
        }    
    }

Once you have a subclass of Canvas that can draw what you want, you need to create an instance of it and put that instance into some JFrame. The message that puts objects into a JFrame is add, which takes the object being put into the JFrame as its only parameter. Thus, for example, if you wanted to display a flat line (via a SimpleCanvas object) in JFrame window, you would have a statement such as

    window.add( new SimpleCanvas() );

in the code that sets up window.

Graphics Objects

You probably noticed that the paint message receives a Graphics object as its parameter. Graphics is a class that represents objects that know how to do simple graphics on Canvas objects (and on other things that can appear in windows).

Each Graphics object draws relative to a pixel coordinate system for the Canvas on which it is drawing -- i.e., a coordinate system whose (0,0) point is the upper left corner of the Canvas, and that measures in units of pixels. In working with this coordinate system, it is sometimes useful to know what the maximum X and Y coordinates are, i.e., the width and height of the Canvas. You can discover these values by sending the Canvas getWidth and getHeight messages. Both messages return the width or height of the Canvas in pixels, and neither has any parameters. Remember, however, that the actual visible coordinates range from 0 to one less than the width or height of the Canvas. Thus, for example, a paint method that needed to know the bounds on the area it could draw in might start like this:

    public void paint( Graphics g ) {
        int maxX = this.getWidth() - 1;
        int maxY = this.getHeight() - 1;
        ... etc. ...

The most important message to Graphics objects for this exercise will be drawRect, which makes a Graphics object outline a rectangle. This message takes four parameters: the X and Y coordinates of the rectangle's upper left corner, and the rectangle's width and height. For example, to make Graphics object g draw a rectangle 10 pixels wide and 50 pixels high, starting at (3,4), you would say

    g.drawRect( 3, 4, 10, 50 );

You can do this exercise with drawRect as the only message you send to Graphics objects. However, here are brief outlines of some other messages that might just be fun to play with:

drawLine draws a line between two points. The parameters are the coordinates of the two points. For example

    g.drawLine( x1, y1, x2, y2 );

fillRect fills a rectangle with color, as opposed to just drawing its outline. The parameters are the same as those to drawRect. For example

    g.fillRect( x1, y1, width, height );

drawOval and fillOval are analogous to drawRect and fillRect, except that they outline or fill an oval instead of a rectangle. Parameters are the upper left corner, width, and height of an invisible rectangle that just fits around the oval.

setColor sets the color in which future drawing will be done. The parameter is a Color object that specifies the desired color. See the Java library documentation for class Color to learn about Color objects.

Exercise

Write a Java program that opens a window on the monitor and displays a certain picture (described below) in it. The program should provide some way for users to stop it, but it needn't provide any other user interaction.

The picture your program should display is really an abstract pattern, drawn in a rectangular region of the window. Suppose the coordinates of the upper-left corner of the region are (x1,y1) and the coordinates of the lower right corner are (x2,y2). Then the pattern is defined as follows:

Here is an example of this pattern. Note that this is a fairly small example, your program should be able to draw patterns of whatever size your Canvas is.

[Recursive Squares]

This is a big exercise if you try to tackle it as one monolithic task. However, if you break it into small steps, it's not so bad (and what questions you have about each step provides a good gauge of what you already know about Java programming and what I should review). I suggest the following steps:

  1. Write a Java program that simply tells you it's running.
  2. Expand this program so that it has a minimal class to represent pictures, and a main method that creates an instance of that class. The "picture" class doesn't have to do anything yet, in particular any methods you define for it can be what are called "stubs" -- methods that can be called as the real ones would, but that do nothing more than print something to standard output to indicate that they are running and perhaps return some dummy value.
  3. Further expand the program so that the "picture" class opens a window on the monitor whenever a "picture" object is created. See the discussion of JFrame in the "Background" section for information on how to open windows. Also in this step, you can write the code that sets any features you want the window to have, e.g., its height or width, whether the program exits when the window closes, etc.
  4. Your program will need its own subclass of Canvas in order to draw the pattern (see the discussion of Canvas in the "Background" section for what the Canvas class is and why you need a subclass of it). So extend the program to include a minimal Canvas subclass, and put an instance of this subclass in the program's JFrame. Don't make the Canvas subclass draw the whole pattern yet, just have it draw something simple like a single line for now.
  5. Finally, finish your Canvas subclass by making it draw the actual pattern. Hint: it may be easiest to do this if you write an auxiliary method in your subclass that does most of the drawing, and just have paint call this auxiliary method with appropriate parameters.

Follow-Up

I will grade this exercise in a face-to-face meeting with you. Make an appointment to meet with me at some time convenient for you, as long as that time is before the end of the due date above. Meetings only need to be 15 minutes long. You can make an appointment by signing up on the copy of my schedule on the bulletin board outside my office.

I would like to read and run your program during our meeting. To do this, you can either bring the program to my office on a laptop computer, or we can go to a lab during the meeting.