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 |