Welcome

to this workshop on

Graphics Java Programming

at MACUL 2011. We'll be programming applets for doing graphics.

Preliminary information

Me

Dr. Susan Haynes
Associate Professor, Computer Science, Eastern Michigan University
shaynes @ emich . edu
http://emunix.emich.edu/~haynes

Resources

This lecture and all source code will be located at http://emunix.emich.edu/~haynes/Papers/MACUL2011

Workshop help

Using a Mac

Turn on computer and login Follow verbal instructions
Logoff and turn off computer Follow verbal instructions
Open an application Finder | Application | ... | Double Left Click
Close a document File | Close or close window with click on red radio button left side of title bar
Quit an application File | Quit
Select text Left click - hold - drag - release
Copy text to clipboard Right click | copy (command-c)
Delete text Right click | cut (command-x)
Paste text Right click | paste (command-v)
Undo command-z
Force quit Apple symbol (top menu bar, far left) | Force Quit | Choose app

Using BlueJ

Open BlueJ Finder | Applications | BlueJ v3.0.4 | BlueJ
Close an open Project Project | Close
Create (and open) new Project Project | New Project | ... navigate to desired location, enter name
Open existing Project Project | Open Project | navigate to desired location.
Create New Applet In IDE, click New Class button, Click Applet, Enter Applet Name
Edit Class (Applet) In IDE, double left click class icon or in IDE, right click class icon | Open Editor
Compile Class (Applet) In IDE, single left click class icon (to select), then click Compile button or in Edit window, click Compile button
Execute Applet In IDE, single right click class icon, then click Run Applet. In Run Applet wizard, click OK.
Remove Class In IDE, single right click class icon, then click Remove
Close appleviewer window Close window

Laboratory 1 Preliminaries

  1. Copy the source code from the USB drive to your Desktop
  2. Open the MACUL2011 folder
  3. Open BlueJ on the project by Double Left Click package.bluej
  4. Run the applet Lab1
  5. Modify the applet using your intuition so the string "Sample Applet" is in red rather than black, and the string "and me" is beneath the "created by BlueJ" string
  6. Close this project
  7. Close BlueJ
  8. Take a breath.
  9. Open BlueJ and the project and run Lab1.
  10. Create a new class named Hello that prints "Hello, world!"
  11. Compile - debug - run until Hello works.

You are probably wondering about all the stubs ( init(), start(), stop(), destroy() ) in the sample applet code. They control the behavior of the applet at different times in the applet's life. We'll talk about these a little more at the end of the workshop. For now, we are only using paint()

Graphics

Relevant Java API references

Graphics http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Graphics.html
Color* http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Color.html
Font* http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Font.html
Abstract Windowing Toolkit http://download.oracle.com/javase/1.4.2/docs/api/java/awt/package-summary.html is a package containing a complete set of classes for drawing and user interfaces. This is why we import java.awt.* to all our applet code.
Swing http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/package-summary.html is a package containing classes for Swing.
Swing Timer http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/Timer.html
ActionListener http://download.oracle.com/javase/1.4.2/docs/api/java/awt/event/ActionListener.html
MouseListener http://download.oracle.com/javase/1.4.2/docs/api/java/awt/event/MouseListener.html
*especially see static members of Color and Font.

The Graphics class is an abstract base that allows drawing on a Component. Since Graphics is an abstract class, you cannot call the constructor directly. We will see later how to get the graphics context from the Component.

There are several Graphics methods. We'll work with the following subset. You can check the Graphics API URL given above for more detail.

drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) 

drawLine(int x1, int y1, int x2, int y2) 

drawOval(int x, int y, int width, int height) 

drawPolygon(int[] xPoints, int[] yPoints, int nPoints) 

drawRectvoid (int x, int y, int width, int height) 

drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) 

drawString(String str, int x, int y) 

fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) 

fillOval(int x, int y, int width, int height) 

fillPolygon(int[] xPoints, int[] yPoints, int nPoints) 

fillRect(int x, int y, int width, int height) 

fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) 

setColor(Color c) 

setFont(Font font) 
Stop and think: What is drawn by the following code? Then we'll run the Rect1 applet.
public void paint(Graphics g)
    {
        g.setColor(Color.black);
        g.drawRect(0, 0, 50, 50);
        g.drawString("A", 5, 10);
        g.setColor(Color.blue);
        g.drawRect(50, 50, 50, 50);
        g.drawString("B", 55, 60);
        g.setColor(Color.red);
        g.drawRect(100, 100, 50, 50);
        g.drawString("C", 105, 110);
    } 

Now what about filled rectangles? Run Rect2 applet to confirm your prediction.

public void paint(Graphics g)
    {
        g.setColor(Color.black);
        g.fillRect(0, 0, 50, 50);
        g.drawString("A", 5, 10);
        g.setColor(Color.blue);
        g.fillRect(50, 50, 50, 50);
        g.drawString("B", 55, 60);
        g.setColor(Color.red);
        g.fillRect(100, 100, 50, 50);
        g.drawString("C", 105, 110);
    }
What happened to the Strings "A", "B", "C"?

What happens when we overlap the figures? Run Rect3 applet.

public void paint(Graphics g)
    {
        g.setColor(Color.black);
        g.fillRect(0, 0, 50, 50);
        g.drawString("A", 55, 10);
        g.setColor(Color.blue);
        g.fillRect(25, 25, 50, 50);
        g.drawString("B", 80, 30);
        g.setColor(Color.red);
        g.fillRect(50, 50, 50, 50);
        g.drawString("C", 105, 60);
    }

Laboratory 2: Practice drawing

Draw a stick man or stick woman that fits inside a bounding box of width X height = 30 X 30.
Then implement a paint() method to make it happen in your new applet Lab2.
Do not spend more than 15 minutes on this. Explore. Don't worry about perfection here.

Coding graphics

Down with magic numbers!! Here's an example applet where I draw 10 black circles from the upper right corner to the lower left corner. This code is in Circles1.java

public void paint(Graphics g)
    {
	  // Component methods to get size of drawing surface
        int height = getHeight();   
        int width = getWidth();
        
        // ok, ok, a magic number for # of circles
        int diameter = Math.min(height, width) / 10;     
        
        g.setColor(Color.blue);
        g.fillRect(0, 0, width , height);   // make background color blue
       
        g.setColor(Color.black);
        
        for (int x = width-diameter, y= 0; 
             x >=0 && y <=height-diameter; 
             x -= diameter, y += diameter)  // u gotta prob with , ?
        {
            g.fillOval(x, y, diameter, diameter);
        }
       
    }

Let's try that again where we vary the colors of the circles. I'm also going to define the class variables height, width, diameter, and the new array of Color up where they belong. Take a look at Circles2.java. I'm pasting only the paint() code here.

public void paint(Graphics g)
    {
              
        for (int i = 0, x = width-diameter, y= 0; 
            i <10 && x >= 0 && y <= height-diameter; 
            i++, x -= diameter, y += diameter)  // u gotta prob with , ?
        {
            g.setColor(colors[ i % colors.length ]);    // wrap around colors
            g.fillOval(x, y, diameter, diameter);
        }
       
    }

Laboratory 3: Programming graphics

You probably really hate my loop control in the most recent paint(). I'm not sure I blame you. In this lab, use iteration (or recursion(!) if you want) to draw several ovals or rectangles. You should cannabilize the Lab2 code to shorten the development time.
For an example task: lay down 20 rectangles from the upper left corner to the lower right corner (the loop control will be much more natural). Name this applet Lab3.

GUI (i.e., SWING (and AWT))

    We are going to talk about animation with GUI control of graphics drawing in four steps:
  1. Using the Swing Timer to animate.
  2. Stop and Start Buttons to turn on and off a Swing Timer
  3. Using input components to control a parameter

In many ways, Swing is an easier to use alternative to AWT. We're going to build GUIs using Swing classes rather than AWT classes because Swing is easier. Caveat! I have found that JButton doesn't work the way I expect. For this reason, I use java.awt.Button rather than javax.swing.JButton.

We've already been importing the package javax.swing.* so that we could use JApplet as a base class for our applets. We could have been using Applet as our base class (only would need java.awt.*), but JApplet simplifies the use of containers for GUIs.

Simple Swing Timer

Here is the API for the Swing Timer: http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/Timer.html The methods of greatest importance to us are: start(), stop(), isRunning(), setDelay().

The API for the ActionListener interface is here: http://download.oracle.com/javase/1.4.2/docs/api/java/awt/event/ActionListener.html We must implement actionPerformed(), which is the code that is executed when a timer "goes off."

The Swing Timer is a nifty class that lets us set up timers. We can start and stop each timer. We can set a delay time for the timer. When the timer "goes off" the specified "listener" code will be executed. Warning, there is a Timer class in java.util.Timer. We don't want to use that one. We want to use javax.swing.Timer.

We'll start with the constructor: Timer(int delay, ActionListener listener)
This constructor creates a Timer object that will "notify" all associated listeners every delay milliseconds. The newly created Timer object has one ActionListener associated with it (listener).

A small example will help. RectRand.java draws a black rectangle at a random location. Every time you run the applet, the rectangle will appear at a different location. I copy RecRand's paint() here:

public void paint(Graphics g)
    {
        x = gen.nextInt(screenWidth - xsize);
        y = gen.nextInt(screenHeight - ysize);
      
        g.fillRect(x, y, xsize, ysize);
    }

In the next applet, Timer1.java, I add a timer that fires every 1000 milliseconds. When the timer fires, the actionPerformed code executes. The actionPerformed code arranges for paint() to be executed in the (near) future: clearing the previous rectangle, then calculating new x,y position and drawing the rectangle.

paint() seems reasonable - it's exactly the same as it was in RectRand, however, CAVEAT actually it's peculiar and only works because there's only one timer. With one timer, it is still reasonable to override paint() by using it to directly draw on the relevant Component whenever the state of the applet changes. However, if you have different objects moving independently, and you want the graphics image to display that, you'll need to use repaint() as shown in a later example.

public void paint(Graphics g)					// for RectRand.java
    {
        g.clearRect(x, y, xsize, ysize);
        x = gen.nextInt(screenWidth - xsize);
        y = gen.nextInt(screenHeight - ysize);
      
        g.fillRect(x, y, xsize, ysize);
    }
The timer listener arranges for the drawing of a new rectangle whenever the timer fires:
class TimerListener implements ActionListener {
        
        public void actionPerformed(ActionEvent e) {
            repaint();                                  // arranges for  paint()
        }
    }

Laboratory 4: Using one timer.

Rewrite your Lab3 so that the rectangles are laid down one every second.

Simple Swing Timer, another example

paint() is automatically made ready to run whenever needed. If the applet needs to paint() itself, then your code will call repaint(). In this second example of using the Swing Timer, Timer2.java, I have two different rectangles that are moving at different intervals. The first timer (timer1) moves (randomly) the first rectangle (b1) every 1 second. The second timer (timer2) moves the second rectangle, b2, every 0.5 second.

You'll notice that paint() only draws b1 and b2. paint() is invoked by the TimerListeners whenever their relative timers go off. The timers, as stated in the previous paragraph, update the position of the relative box and calls repaint() (forcing the paint() method to redraw the current position of b1 and b2.

Laboratory 5: Messing with the two boxes

This is intended to be an easy lab. Do the "way easy" problem, or the "easy" problem.

"Way easy": Mess about with the constructions of b1 and b2, changing their sizes and colors. Also, mess with the delay for timer1 and timer2.

"Easy": Write a new class: AnOval that does the same thing that ARect does, only it draws and moves a circle.


Button to control execution

The first example ButtonDemo.java is an easy one that controls a text string drawn on the canvas.

Here is the relevant code:

public class ButtonDemo extends Applet implements ActionListener
{
    String msg = "";
    Button yes, no, maybe;
    
    public void init()
    {
   
        yes = new Button("YES");
        no = new Button("NO");
        maybe = new Button("MAYBE");
        
        add(yes);
        add(no);
        add(maybe);
        
        yes.addActionListener(this);
        no.addActionListener(this);
        maybe.addActionListener(this);
    }

public void actionPerformed (ActionEvent e) {
        String str = e.getActionCommand();
        if (str.equals("YES")) msg = "You pressed YES";
        else if (str.equals("NO")) msg = "You pressed NO";
        else if (str.equals("MAYBE")) msg = "You pressed maybe";
        else msg = "UH OH!!!";
        
        repaint();
    }
    Notice a few things here:
  1. I'm using Button (java.awt.Button) rather than JButton (javax.swing.JButton). Since I'm not using any Swing component the class ButtonDemo extends Applet (not Japplet).
  2. ButtonDemo implements ActionListener, rather than defining a new class that implements ActionListener.
  3. Because ButtonDemo implements ActionListener, ButtonDemo must implement actionPerformed(). Each button is linked to its actionPerformed through a statement like, e.g., yes.addActionListener(this).
  4. This style of programming actionPerformed must distinguish between different events (there are three different events). It does this through the getActionCommand() method.

    Stop and Start Buttons to turn off and on the animations

    With the Swing Timers, it's now easy to turn on and off the animations by using the Swing Timer's start() and stop() method.

    In Timer1a.java, I've added a start button and a stop button. The start button with turn on Timer timer with timer.start(). The stop button will turn off timer with timer.stop(). Each button will have an ActionListener that listens for the button press.

    Laboratory 6: Change the timer delay

    The javax.swing.Timer.setDelay(int delay) method will change the delay of an instantiated timer. Can you change Timer1a by adding a third button that changes the delay to 1/2 second and a fourth button that changes the delay to 1 second?

    Using the mouse

    See the code MouseClicks.java. Mouse information is obtained via two different listeners. A MouseListener, which is used in this applet, and a MouseMotionListener. The MouseListener requires implementation of five methods. In this applet, I'm just repositioning the cat by clicking at a point. The MouseListener takes the (x,y) coordinate and sets the cat's (x,y) to it.

    Laboratory 7: Can you cannibalize this code to move your stick man instead of the cat? Also speed up the timer to get more motion effect.

    Embedding an applet to a web page

    Many IDEs are able to create an html page with an embedded applet. BlueJ can do this.

    More generally, you can use the <applet> tag in an HTML page:

    <applet code="Circles1.class" width="350" height="350">
    Java applet that draws circles.
    </applet>
    
    For an example html document see Circles1.html, and view the source.

    Laboratory 8: an applet in an html page

    1. Open a plain text editor (The BlueJ editor is a plain text editor).
    2. Cannibalize from Circles1.html to run a different applet.
    3. Save with extension ".html"
    4. Open browser, Choose File | Open File ... and navigate to your html document.

    That's all folks! Thanks for participating. I hope you can take something back with you.