CSC 160-2 Lab 7-1 Inheritance and Graphics

A Panel displaying a centered Name

We want to write a program that displays a panel with a given name centered. We want the panel to behave in such a way that no matter how the panel is resized, the name always stays centered.

We will create a subclass of JPanel. called NamePanel. This subclass will remember the name it is supposed to display. The name will be passed to it via its constructor. The main method will be really short: it just creates a JFrame, creates an NamedPanel with a string name to display, adds the NamePanel to the frame, and displays the frame.

Create a Main class with a main method

Begin by creating a Java project with the following main method:

   public static void main(String[] args)
    {
        JFrame frame = new JFrame("Centered Name");
        NamePanel customPanel = new NamePanel("North Central College");
        frame.add(customPanel);
        
        // Usual frame stuff
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    

Notice that this code will not compile until after you have created the NamePanel class, which is described below.

Here is how to write the NamedPanel class. Start by extending the JPanel class. The NamedPanel class goes in the same file, before or after the Main class.

class NamePanel extends JPanel
{

}
    

This class needs a String variable to store the name that will be passed to its constructor. This name will never be changed, so we can declare it to be final, a keyword that says that once a variable has been assigned a value, that value cannot be changed. The class also needs a variable to store the width of the string in the font used by the panel. The width of a string is the width in pixels of a rectangular box that tightly fits around the string when the string is drawn.

class NamePanel extends JPanel
{
    // final keyword means once a value is assigned
    // it can never be changed.
    private final String name;
    private final int strWidth; 
}   
    

Next, you need a constructor that will be passed a name, store the name into the class variable, and then compute the width of the string. Write a constructor for the NamePanel class that takes a parameter name1 of type String and executes the following code

        name = name1;    
        // Get the font for the panel, and get the width of 
        // the name string in the panel's font
        Font font = this.getFont();
        FontMetrics fm = this.getFontMetrics(font);
        strWidth = fm.stringWidth(name);
        // Set the foreground and background color of the panel
        this.setForeground(Color.BLUE);
        this.setBackground(Color.WHITE);   

    

Remember that when you use pack() on a frame, the frame squeezes everything in it down to its preferred size. The preferred size of a component is determined by what it contains. A panel, however, will have a preferred size of zero width by zero height if it contains no user interface components, unless you explicitly set its preferred size. Add code to the constructor that sets the preferred size of the NamedPanel to a width and height of twice the width of the name string:

this.setPreferredSize(new Dimension(2*strWidth, 2*strWidth));
    

At this point, you should be able to run the program. Unfortunately, the name in the panel does not show up. For the name to show up, we need to override the paintComponent method of JPanel so that it draws the name string centered in the panel.

    public void paintComponent(Graphics g)
    {
        // Call the superclass version of this method
        // to erase the panel
        super.paintComponent(g);       
        // Write the name string centered in the panel
        int x = (this.getWidth() - strWidth) /2;
        int y = this.getHeight() /2;
        g.drawString(name, x, y);
    }
    

At this point, you should be able to run the program and see the name centered in the panel.

Experimenting with Fonts

Google the phrase Java 8 Component. Scroll down the documentation, and find and read the entries on the methods

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

Look at how these methods are used in the example program above. Then, google java 8 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.

You can view a list of common fonts in Windows at this Wikipedia site.

As an example, you can modify the font in the panel this way:

        Font font = new Font("Cambria", Font.BOLD, 24);
        this.setFont(font);
        //Font font = this.getFont();
        FontMetrics fm = this.getFontMetrics(font);
        strWidth = fm.stringWidth(name);
    

Making these changes and running the program gives a different and a bigger font:

The Graphics2D Class

When the paintComponent method is called, it is actually passed an object of the Graphics2D class. This class is a subclass of the Graphics class which adds methods for doing 2D graphics, that is, graphics in two dimensions. To use the methods of this subclass, we must cast the parameter passed to paintComponent to Graphics2D:

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

After the cast, we use the g2D object.

Experimenting with Rotations

Modify the program so that you have a larger height for the preferred size for the panel. Do this by modifying the statement in the constructor that sets the preferred size:

 this.setPreferredSize(2*strWidth, 2*strWidth));

Next, modify the paintComponent method by adding the statement

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

Just before the statement to draw the string. This time though, draw the string beginning at the bottom of the panel instead of halfway down. The effect is to draw the string after the drawing surface has been rotated through an angle of π divided by 24 radians. You should see this:

Note that the argument to the rotate is negative. This has the effect of rotating the drawing surface by an angle of π/24 in an anti-clockwise direction.

Exercise

Figure out how to draw the string sloping downward at the same angle, instead of sloping upwards. The string should start near the top of the panel and then slope downwards, like this:

Look at these images. 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? If you have a problem doing this, read on to find out about another overload of the rotate() method.

Consider the second overload of the Graphics2D.rotate() method.

		void rotate(double theta, double cx, double cy)		
		

This method has the effect of rotating the drawing surface with the center of the rotation being the given parameters cx and cy. Experiment with it by using different angles for theta and different positions for the cx and cy. See if you can figure out what this overload of rotate does. In particular, just before drawing a string, call the above method to rotate the drawing surface.

Lab Assignment to Hand in

Write a program that display a propeller right in the center of a panel. The propeller should have eight points (a plus sign has 4 points) arranged so that all points are the same distance away from their neighboring points. The propeller should stay in the center of the panel even if the panel is resized.

Due Date: Saturday at end of Week 7.