CSC Lab 2-2: Graphics and Animation

Let us start with the Graphics. Use cut and paste to get the following program into Netbeans, get it to compile, and run it.

package lab2_2progs;

import javax.swing.JPanel;
import java.awt.*;
import javax.swing.JFrame;

public class Main
{
    public static void main(String[] args)
    {
       new MyFrame();
    }
}

class MyPanel extends JPanel
{
    private String str = "Hello Java Graphics!";
    int strWidth;   // Width of string in the component's font.
    public MyPanel()
    {
        // Get the font and FontMetrics object and measure the string's width
        Font font = this.getFont();
        FontMetrics fm = this.getFontMetrics(font);
        strWidth = fm.stringWidth(str);
        // Set the foreground and background color of the panel
        this.setForeground(Color.PINK);
        this.setBackground(Color.WHITE);        
    }

    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);  // Call the super class method to erase
        Graphics2D g2D = (Graphics2D)g;     

        // Compute the x and y so the string will be centered in the panel
        int x = (getWidth() - strWidth)/2;
        int y = getHeight()/2;

        // Draw the string
        g2D.drawString(str, x, y);
    }
}

class MyFrame extends JFrame
{
    public MyFrame()
    {
       // Set title of frame
       super("Graphics Fun");
       // Create and add the panel
       add(new MyPanel());
       // Usual stuff to size and show frame
       setSize(400, 200);
       setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       setVisible(true);
    }
}

You should see a screen similar to what is shown below.

Experimenting with Fonts

Googgle the phrase Java 6 Component. Scroll down the documentation, and find and read the entries on the methods

Font getFont()
void setFont()
FontMetrics getFontMetrics(Font f)

Look at thow these methods are used in the example program above. Then, google java 6 Font. Look at the documentation for these Font constructors and methods:

Font(String name,  int style,  int size)   //constructor
String getName()
int getStyle()     // style can be Font.PLAIN, Font.BOLD, Font.ITALIC, or Font.BOLD|Font.ITALIC.
Font deriveFont(float size)
Font deriveFont(int style)
Font deriveFont(int style, float size)

A font has a name, a style, and a size. Given a font, you can derive a similar font of different size, or style. Or if you know the name of the font, you can use the constructor to get the font in a specified style and size.

Caution: if you use deriveFont() to derive a font of a different size, be sure the argument is a float and not an int. Otherwise, you will call the variant that derives a font with an int style value! For example, if you are passing in an integer obtained from the getSize() method on the font, you must cast it to a float.

Use this knowledge you have just gained to cause the program to display your name in a font that is twice as big as the regular size for the font.

Experimenting with Rotations and Translations

Insert the statement

 g2D.rotate(-Math.PI/24);

just before the statement to draw the string. This has the effect of rotating the drawing surface of the Graphics context by an angle of π /24 in a clockwise direction, and then drawing the string. The effect is that the string is drawn at an angle, as shown here. Note that rotating the drawing surface in a clockwise direction makes it look like the string was rotated the same angle in the opposite direction.

Figure out how to write your name slanted downwards at an angle, instead of upwards.

Can you figure out how to write your name straight up? Can you figure out how to write your name straight down? Can you do other fancy effects with text? Can you make a plus sign? A propeller? Hint: consider the second overload of the Graphics2D.rotate() method.

Enough of simple graphics with text. Now, let us see how we can use a timer to do some animation.

Text Animation

We are going to use a timer to animate the text and make it move across the width of the JPanel. To do this, create a new Project in Netbeans called TextAnimation. Then, copy the code from the first project into your second project. Start by modifying the code so that the JPanel displays the string at its left edge, but midway down. When you run the program, it should look like what you see on the right.

How can we get the text to glide smoothly across the JPanel? We will create a javax.swing.Timer timer, and let the actionPerformed of the timer listener control the x coordinate of where paintComponent draws the string. At each timer event, the actionPerformed method will increment x by a small step, say 5; and then tell the JPanel to repaint. The paintComponent method will then compute the y coordinate as before, to keep the string vertically centered. The paintComponent method will not compute x though: it will use the value that was computed by the actionPerformed method. This will cause the string to be drawn slightly to the right of its previous position.

Where shall we put the ActionListener? Clearly, both the actionPerfomed method in the listener, and paintComponent in the JPanel need access to the x coordinate. It is best to put the actionPerformed method in the JPanel, and just let x be an instance field of the class:

class MyPanel extends JPanel implements ActionListener
{
    private String str = "Hello Java Graphics!";  // String to display
    private int x = 0;                            // x coord of string position
    private int step = 5;                         // step size
    int   strWidth;                               // measure of string width

    Timer timer = new Timer(100, this);          // timer used to run the animatio

    // Constructor measures the width of the string in the panel's font
    // and starts the timer
    public MyPanel()
    {
        
    }    
    // Draws the string at x-coordinate x, and y-coordinate
    // computed from the height of the panel to vertically center the string.
    public void paintComponent(Graphics g)
    {
       
    }

    // Increments the x position of the string by step and
    // asks the panel to repaint itself. When the string bumps against the
    // right edge of the panel, it stops the timer.
    public void actionPerformed(ActionEvent e) 
    {
       
    }
}

Note how our MyPanel class extends JPanel and implements ActionListener at the same time.

Fill in the missing code in these methods. Run the program and verify that the string glides across the JPanel and stops at the right edge.

Drawing Geometric Shapes

A geometric shape such as a rectangle or ellipse is drawn or filled with the draw(Shape s) and fill(Shape s) methods. To define a shape, use one of the java.awt.geom classes such as

Rectangle2D.Double
Ellipse2D.Double

For example, to fill an ellipse whose bounding box has its top left corner at (x = 5, y = 10) that has width 20 and height 30, insert the following code in the paintComponent method:

 Ellipse2D.Double ellipse = new Ellipse2D.Double(5, 10, 20, 30); 
 g2D.fill(ellipse);
 

If you want to fill the ellipse with a yellow color and draw its boundary in black, then use the following code.

 // Create the ellipse shape 
 Ellipse2D.Double ellipse = new Ellipse2D.Double(5, 10, 20, 30);
 // Set the  color in the Graphics context to YELLOW
 g2D.setColor(Color.YELLOW);
 // Fill the created ellipse with the current color, which is YELLOW
 g2D.fill(ellipse);

 // Set the color in the Graphics context to BLACK
 g2D.setColor(Color.BLACK);
 // draw the outline of the ellipse in the current color, which is BLACK
 g2D.draw(ellipse);

What to hand in

Write a program that animates either text, or a geometric shape such as an ellipse or a rectangle, or both text and a geometric figure. The animation should not stop until the frame is closed. The object (text or shape) starts at the left edge of the panel, and slowly glides to the right. The shape (or shapes) reverses its direction of motion when it bumps against the right edge of the panel. It then starts moving to the left at the same speed. When it bumps against the left edge, it again reverses direction and starts moving to the right. This continues until the frame is closed.

This lab is due Next Wednesday at midnight. This material will be on the test next Friday.