Simple Graphics

A panel uses a screen coordinate system for drawing graphical shapes.  Unlike the Cartesian coordinate system, the origin (0,0) for screen coordinates is in the upper left corner of the panel.  The x-axis and is at the top boundary of the panel and the y-axis is its the left boundary.  The x values increase to the right, as usual, but the y values increase to the bottom.  For example, the point (50, 50) is located 50 pixels to the right of the y-axis and 50 pixels below the x-axis.  Negative coordinates exist but are not viewable outside of the boundaries of a panel.  The window can be resized to view positive coordinates that lie beyond the current right and bottom boundaries of a panel. Each panel has its own coordinate system that is separate from those of other panels and from that of the enclosing window.

As you saw earlier, a panel has a background color, which is painted at program startup and can be changed under program control. A panel's dimensions (width and height) change when the dimensions of the enclosing window change. 

Each panel also maintains its own graphics object, an instance of the java.awt.Graphics class, to which graphical shapes can be drawn. The graphics object maintains a drawing color (distinct from the panel's background color) and a font that are used to draw graphical shapes or text. Some of the drawing methods are summarized in the next table.

 

java.awt.Graphics Method

What it does

setColor(newColor)

Sets the drawing color to the new color.

setFont(newFont)

Sets the drawing font to the new font.

drawLine(x0, y0, x1, y1)

Draws a line segment between the specified end points.

drawRect(x, y, width, height)

Draws a rectangle with the given corner point, width, and height. The method fillRect behaves in a similar manner, but fills the rectangle with the current drawing color.

drawOval(x, y, width, height)   

Draws an oval within an imaginary rectangle with the given corner point, width, and height. The method fillOval behaves in a similar manner, but fills the oval with the current drawing color.

drawText(text, x, y )

Draws the text whose left baseline begins at the given point.

 

The drawing of shapes or text within a panel is best done in the context of the panel's paintComponent method. This method is automatically triggered whenever the main window is "refreshed" (popped up at startup or after being minimized or resized). As such, paintComponent is like an event handler for output to a panel. The method expects a graphics object as an argument, and the programmer runs one or more of the methods mentioned above to draw things in the panel. You can also execute this method under program control, by calling the panel's repaint method.

The first example program shows some of these methods in action. The program 's main window holds a single panel, and the coordinates of the panel's center point (not its origin!) are displayed at startup. When the user resizes the window, the coordinates of the centerpoint are redisplayed accordingly. The next screen shots show this effect:

 

Note that the coordinates of the centerpoint are 1/2 of the panel's width and height in each case (the window's initial dimensions are 300 by 300, so its borders must occupy a pixel of width or height, and its title bar must occupy 10 pixels of height).

When the method paintComponent is called, the panel uses its getWidth and getHeight methods to determine its current dimensions and divides these values by 2 to obtain the new centerpoint to display. Here is the code for the first panel class, in the file GraphicsPanel1.java: 

 

import BreezySwing.*;

import java.awt.*;

 

public class GraphicsPanel1 extends GBPanel{

 

    public GraphicsPanel1(Color color){

        setBackground(color);

    }

 

    public void paintComponent (Graphics g){

        // Clear the panel and redraw the coordinates

        super.paintComponent(g);

        int mouseX = getWidth() / 2;

        int mouseY = getHeight() / 2;

        g.drawString("(" + mouseX + "," + mouseY + ")", mouseX, mouseY);

    }

 

}

 

To run this program, and every other program in the next few examples, you edit the file GraphicsDemo.java to create the appropriate type of panel object and then recompile. Here is the main window code that runs the first example:

 

import javax.swing.*;

import BreezySwing.*;

import java.awt.Color;

 

public class GraphicsDemo extends GBFrame{

 

    GBPanel panel = addPanel(new GraphicsPanel1(Color.pink), 1,1,1,1);

 

    public static void main (String[] args){

        JFrame frm = new GraphicsDemo();

        frm.setSize (300, 300);

        frm.setVisible (true);

    }

 

}

 

The first example program always displays the panel's centerpoint. But suppose you want to display the current mouse coordinates each time you click the mouse in the panel, as shown in the next screen shots:

 

 

To handle that, you add to your panel class a mousePressed method and a pair of instance variables for the coordinates. When the user clicks the mouse in the panel, mousePressed resets the instance variables to the current mouse coordinates (the arguments of mousePressed) and calls repaint(). This has the effect of calling paintComponent to refresh the panel. paintComponent now displays the values of the two instance variables, rather than the position of the panel's centerpoint. We can provide a custom font and color for the text as well. Here is the code for the new panel class, in the file GraphicsPanel2.java:

import BreezySwing.*;

import java.awt.*;

 

public class GraphicsPanel2 extends GBPanel{

 

    // Initial coordinates drawn at startup

    private int mouseX = 100, mouseY = 100;

 

    public GraphicsPanel2(Color color){

        setBackground(color);

    }

 

    public void paintComponent (Graphics g){

        super.paintComponent(g);

        Font font = new Font("Verdana", Font.BOLD, 16);

        g.setFont(font);

        g.setColor(Color.blue);

        g.drawString("(" + mouseX + "," + mouseY + ")", mouseX, mouseY);

    }

 

    public void mousePressed(int x, int y){

        // Reset coordinates and refresh the panel

        mouseX = x;

        mouseY = y;

        repaint();

    }

}

 

When you run the second program, you'll note that each mouse click erases the old pair of coordinates before drawing the current pair of coordinates. The reason for this lies in the first line of code in the paintComponent method. This code, super.paintComponent(g), calls the same method in your panel's parent class, GBPanel. This method in turn calls the same method in its parent class, JPanel. This instance of the method finally does something - it clears the panel by repainting it in its background color. Thus, when control returns to the next line of code in your own paintComponent method, the panel is effectively empty, and any of its contents must be drawn anew. 

Now suppose you want the panel to retain earlier things drawn in it, like the previous pairs of coordinates drawn in our second example. Here are screen shots of this new program's main window:

 

 

In this case, your panel will have to remember the earlier values in a separate data structure, such as a list. Then, when the user clicks the mouse, the new coordinates are added to this data structure, rather than saved in a single pair of integer instance variables. When repaint is called, the paintComponent method runs through the list of coordinates, drawing each pair to the panel. Here is the code for the new panel class, in the file GraphicsPanel3.java:

import BreezySwing.*;

import java.awt.*;

 

public class GraphicsPanel3 extends GBPanel{

 

    private java.util.List<Point> points = new java.util.ArrayList<Point>();

 

    public GraphicsPanel3(Color color){

        setBackground(color);

    }

 

    public void paintComponent (Graphics g){

        // Clear the panel and redraw all the points

        super.paintComponent(g);

        Font font = new Font("Verdana", Font.BOLD, 16);

        g.setFont(font);

        g.setColor(Color.blue);

        for (Point point : points){

            int mouseX = (int)Math.round(point.getX());

            int mouseY = (int)Math.round(point.getY());

            g.drawString("(" + mouseX + "," + mouseY + ")", mouseX, mouseY);

        }

    }

 

    public void mousePressed(int x, int y){

        // Add the current mouse coordinates to the list of points and refresh the panel

        Point p = new Point(x, y);

        points.add(p);       

        repaint();

    }

}

 

This version makes use of a new class, java.awt.Point, to represent a pair of coordinates. In a sense, the last two program examples use the model/view/controller pattern. The data model is either a single pair of coordinates, or a list of them. The controller responds to each mouse press by updating this model, and then refreshing the view with the model's contents. We will see this pattern at work in our remaining graphics examples. 

 

Back to tutorial Next topic: Responding to mouse events