Simple Graphics Simple graphics are similar under BreezyGUI and the native AWT. The major difference is that under the AWT
graphics are done in a special component called a canvas whereas under BreezyGUI they are
done directly in the interface window. As
usual BreezyGUI provides greater simplicity at the cost of less control. Coordinate SystemsThe basis of any graphics application is a coordinate
system. Positions in this system are
specified in terms of points. Points in a
two-dimensional system have x and y coordinates.
For example, the point (10, 30) has an x
coordinate of 10 and a y coordinate of 30. The x and y coordinates of a point express its position
relative to the systems origin at (0, 0). Figure 1 presents some
examples of points in the familiar Cartesian coordinate system.
Figure 1: A Cartesian
coordinate system. In Java and many other programming languages, the coordinate system
is oriented as shown in Figure 2. Note that
the only quadrant shown is the one that defines the coordinates of the computers
screen, extending down and right from the point (0, 0) in the upper left corner. The other three quadrants exist, but the points in
them never appear on the screen.
Figure 2: Java's
coordinate system. In a windows-based application, the coordinate system is usually relative to a given window. Thus, the origin (0, 0) is at the upper left corner of the window. Each point in the coordinate system locates the position of a pixel, or picture element, in the window. The (x, y) coordinates of a point are represented as integers. The Graphics ClassJava provides a Graphics
class for drawing in a window. A window
maintains an instance of this class, called a graphics context, that allows the programmer to
access and modify the windows bitmap. The
programmer sends messages to this graphics context to perform all graphics operations. Hereafter, we refer to the graphics context with
the variable name g. Some commonly used Graphics
drawing methods are listed in the next table:
Figure 3: Summary of
common drawing methods. The methods fillArc,
fillRect,
and fillOval
draw filled shapes. In the examples that
follow, we assume that the variable g
represents the graphics context of the current window, which is 200 pixels wide and
200 pixels high. Drawing TrianglesThe following code segment draws a triangle with vertices (50, 50),
(100, 100), and (0, 100): g.drawLine(50, 50, 100, 100); g.drawLine(100, 100, 0, 100); g.drawLine(0, 100, 50, 50); Note that the origin (0,0) is at the upper left corner of the
window's border and the vertex (0, 100) is also on the window's border (Figure 4).
Figure 4: Drawing of
a triangle. Drawing CirclesThe next code segment draws five expanding circles as shown in Figure
5. int x = 50, y = 50, width = 50, height = 50; int i; for (i = 1; i <= 5; i++){ g.drawOval (x, y, height, width); width = (int) (width * 1.25); height = (int) (height * 1.25); }
Figure 5: A sequence of expanding circles. Drawing TextThe following code segment draws the string "Java is way cool!" at position (100, 100), as displayed in Figure 6. g.drawString ("Java is way cool!", 100, 100);
Figure 6: Drawing
text. Accessing a Graphics ContextNow that we have seen how to use graphics methods, it is natural to
ask how an application accesses a windows graphics context. The easiest way to do this is to invoke the method
getGraphics(). This method returns the graphics context for the
window. Thus, the following code draws the
string displayed in Figure 6. Graphics g = getGraphics(); g.drawString ("Java is way cool!", 100, 100); Text PropertiesText, that is a string of characters, is drawn like any other image
in a bitmapped display. Text can have several
properties, as shown in the following table:
The color and font properties of text are set by adjusting the color
and font properties of the window (or window object) in which the text is drawn. We first provide an overview of Java's Font
class, and then show some examples of how to control the properties of text. The Class FontAn object of class Font
has three basic properties: a name, a style, and a size.
The following code creates one Font object to represent the font Courier bold 12,
and another Font
object to represent the font Arial bold
italic 10: Font courierBold12 = new Font("Courier", Font.BOLD, 12); Font arialBoldItalic10 = new Font("Arial", Font.BOLD + Font.ITALIC, 10); The Font
constants PLAIN,
BOLD,
and ITALIC
define the font styles. The font size is an
integer representing the number of points, where one point equals 1/72 of an inch. The values of the font names depend on your
particular computer platform. To see what
they are, run the code segment String fontNames[] = Toolkit.getDefaultToolkit().getFontList(); int i; for (i = 0; i < fontNames.length; i++) System.out.println (fontNames[i]); This code
The next table lists the important Font
methods:
Setting the Color and Font Properties of TextThe programmer sets the color and font properties of text by setting
the color and font properties of the GUI object's graphics context. For example, assume that we want to display the
text "Hello
world!", in green with the font Courier bold 14, in an application window. The following code would do this: Font ourFont = new Font ("Courier", Font.BOLD, 14); Color ourColor = Color.GREEN; Graphics g = getGraphics(); g.setColor (ourColor); g.setFont (ourFont); g.writeString ("Hello world!", 100, 100); Changing the font and color of a graphics context affects all
subsequent graphics operations (drawString,
in particular) in that context, but does not alter the font or color of existing images. The Method paintWe now know how to make drawings, but two problems remain. First, graphics cannot be done in constructors, so
how does one display a drawing when a window first opens?
Second, every time a window is resized or uncovered, the window is refreshed and
drawings in the window are lost. We call this
the transient
image problem. There is a common
solution to both problems. One of GBFrame's
superclasses contains a method called paint
that is called automatically when a window first opens and every time it is refreshed
thereafter. Normally, paint
does nothing, but we can override it in our applications and load it up with the desired
drawing instructions. The paint
method has one parameter, which is of type Graphics. Here is an example: public void paint (Graphics g){ g.drawString ("Java is way cool!", 100, 100); } The string "Java
is way cool!" is now displayed when the window first opens and every time the
window is refreshed. The Method repaintAlthough an application can call the paint
method to reapply a group of drawing commands, there is generally little point in it doing
so. Before reapplying drawing commands, one
normally would want to erase the current drawing first.
The repaint
method provides the needed capability. This
method, which is also implemented in one of GBFrame's
superclasses, first erases the current drawing and then calls paint. Actually, repaint
does more. It also tells all the window
components (text fields, labels, buttons, and so forth) to redisplay themselves as well. If one calls repaint
in an application that does not implement paint,
the effect is to erase all drawings in the application's window. ColorA Java programmer can control the color of images by using the Color
class. The Color
class provides the class constants shown in Table 1.
Table 1: Color
constants. Thus, the expression Color.red
would yield the Color
constant for red. The Graphics
class provides the following methods for examining and modifying the color of images:
Images are drawn in the current color until the color is changed. Changing the color does not affect the color of
previously drawn images. The next code
segment draws a string in red and a line in blue in the graphics context g: g.setColor (Color.red); g.drawString ("Colors are great!", 50, 50); g.setColor (Color.blue); g.drawLine (50, 50, 150, 50); Java allows the programmer finer control over colors by using RGB
(red/green/blue) values. In this scheme,
there are 256 shades of red, 256 shades of green, and 256 shades of blue. The programmer "mixes" a new color by
selecting an integer from 0 to 255 for each color, and passing these integers to a Color
constructor as follows: new Color (<int for red>, <int for green>, <int for blue>) The next code segment shows how to create a random color with RGB
values: // Create a random color from randomly generated RGB values int r = (int) (Math.random() * 256); int g = (int) (Math.random() * 256); int b = (int) (Math.random() * 256); Color randomColor = new Color (r, g, b); The value 0 indicates the absence of a color in the mixture, while
the value 255 indicates the maximum saturation of that color. Thus, the color black has RGB (0, 0, 0), and the
color white has RGB (255, 255, 255). There
are 256 * 256 * 256 = 224 possible colors in this scheme. Example 1: Drawing Text at Different PositionsThe next program draws text at different positions in a window. The application allows the user to enter some text
and a point. The Draw option in the Command menu then draws the text at the specified
point. The Clear option in the Command menu erases all of the drawings done so
far in the window. The proposed interface is shown in Figure 7.
Figure 7: Interface
for the text drawing program In this screenshot, the following data were entered:
Here is the code: import java.awt.*; import BreezyGUI.*; public class DrawText extends GBFrame{ MenuItem drawItem = addMenuItem ("Command", "Draw"); MenuItem clearItem =
addMenuItem ("Command", "Clear"); Label textLabel = addLabel ("Text", 1, 1, 1, 1); TextField textField = addTextField ("", 1, 2, 1, 1); Label xLabel = addLabel ("x", 1, 3, 1, 1); IntegerField xField = addIntegerField (0, 1, 4, 1, 1); Label yLabel = addLabel ("y", 1, 5, 1, 1); IntegerField yField = addIntegerField (0, 1, 6, 1, 1);
public DrawText(){ setTitle ("Drawing Text"); } public void menuItemSelected (MenuItem mi){ if (mi == drawItem) draw(); else if (mi == clearItem) repaint(); } private void draw(){ String text = textField.getText(); int x = xField.getNumber(); int y = yField.getNumber(); Graphics g = getGraphics(); g.drawString (text, x, y); } public static void main (String[] args){ Frame frm = new DrawText(); frm.setSize (350, 200); frm.setVisible (true); } } Example 2: Graphing Numeric DataNow we present a program that allows the user to enter the numbers of
students receiving the grades A, B, C, D, and F and to view these data in a line graph, a
bar graph, or a pie chart. Here are some snapshots of the interface showing three different
views of the data:
Above the drawing area are entry fields labeled with each letter
grade. The default value of the number of
students receiving each grade is zero. The
user can select the option Line, Bar, or Pie
from the Graph menu to display the data in the
desired format. When a menu option is
selected, the data in the fields are transferred to an array of grades, and the desired
type of graph is displayed. The default graph type at program startup is a line graph. We leave as an exercise the task of labeling the
graphs with appropriate text. Here is the code: import java.awt.*; import BreezyGUI.*; public class GraphTest extends GBFrame{ Label aLabel = addLabel ("A", 1, 1, 1, 1); IntegerField aField = addIntegerField (0, 1, 2, 1, 1); Label bLabel = addLabel ("B", 1, 3, 1, 1); IntegerField bField = addIntegerField (0, 1, 4, 1, 1); Label cLabel = addLabel ("C", 1, 5, 1, 1); IntegerField cField = addIntegerField (0, 1, 6, 1, 1); Label dLabel = addLabel ("D", 1, 7, 1, 1); IntegerField dField = addIntegerField (0, 1, 8, 1, 1); Label fLabel = addLabel ("F", 1, 9, 1, 1); IntegerField fField = addIntegerField (0, 1, 10, 1, 1); MenuItem lineItem = addMenuItem ("Graph", "Line"); MenuItem barItem = addMenuItem ("Graph", "Bar"); MenuItem pieItem = addMenuItem ("Graph", "Pie"); private final int NUM_GRADES = 5; private final int X_LEFT = 100; private final int X_RIGHT = 300; private final int Y_TOP = 100; private final int Y_BOTTOM = 250; private final int BAR_WIDTH = 10; private int totalXPixels, totalYPixels; private int grades[]; private char graphType; public GraphTest(){ int i; grades = new int[NUM_GRADES]; for (i = 0; i < grades.length; i++) grades[i] = 0; totalXPixels = X_RIGHT - X_LEFT + 1; totalYPixels = Y_BOTTOM - Y_TOP + 1; graphType = 'L'; } public void menuItemSelected (MenuItem mi){ if (mi == lineItem) graphType = 'L'; else if (mi == barItem) graphType = 'B'; else if (mi == pieItem) graphType = 'P'; repaint(); } public void paint (Graphics g){ getInputData(); switch (graphType){ case 'L': drawLineGraph(g); break; case 'B': drawBarGraph(g); break; case 'P': drawPieGraph(g); break; } } private void getInputData(){ grades[0] = aField.getNumber(); grades[1] = bField.getNumber(); grades[2] = cField.getNumber(); grades[3] = dField.getNumber(); grades[4] = fField.getNumber(); } private void drawLineGraph (Graphics g){ int i, x1, y1, x2, y2, largestNumber, xIncrement, yIncrement; drawAxes(g); // Compute the x and y increments. largestNumber = findLargest(grades); xIncrement = totalXPixels / NUM_GRADES; if (largestNumber == 0) yIncrement = 0; else yIncrement = totalYPixels / largestNumber; // Set the initial end point. x1 = X_LEFT; y1 = Y_BOTTOM; // Compute and plot the data points. for (i = 0; i < NUM_GRADES; i++){ x2 = getXCoordinate(i + 1, xIncrement); y2 = getYCoordinate(grades[i], yIncrement); g.fillOval(x2, y2, 5, 5); g.drawLine(x1, y1, x2, y2); x1 = x2; y1 = y2; } } private void drawBarGraph (Graphics g){ int i, x, y, height, largestNumber, xIncrement, yIncrement; drawAxes(g); // Compute the x and y increments. largestNumber = findLargest (grades); xIncrement = totalXPixels / NUM_GRADES; if (largestNumber == 0) yIncrement = 0; else yIncrement = totalYPixels / largestNumber; for (i = 0; i < NUM_GRADES; i++){ x = getXCoordinate (i + 1, xIncrement); y = getYCoordinate (grades[i], yIncrement); x = x - BAR_WIDTH / 2; height = Y_BOTTOM - y + 1; g.fillRect(x, y, BAR_WIDTH, height); } } private void drawPieGraph (Graphics g){ int totalUnits, centerX, centerY, radius, unitAngleSize, startAngle, i; // Set up center point and radius of the pie, and the unit angle size. totalUnits = sum(grades); centerX = getSize().width / 2; centerY = getSize().height / 2; radius = centerX - centerX / 3; centerX = radius; centerY = centerY - centerY / 3; if (totalUnits == 0) unitAngleSize = 0; else unitAngleSize = 360 / totalUnits; startAngle = 0; // Draw the wedges in the pie. for (i = 0; i < NUM_GRADES; i++){ int centralAngle = unitAngleSize * grades[i]; g.setColor(intToColor(i)); g.fillArc(centerX, centerY, radius, radius, startAngle, centralAngle); startAngle = startAngle + centralAngle; } g.setColor(Color.black); } private void drawAxes(Graphics g){ g.drawLine(X_LEFT, Y_TOP, X_LEFT, Y_BOTTOM); g.drawLine(X_LEFT, Y_BOTTOM, X_RIGHT, Y_BOTTOM); } private int getXCoordinate(int i, int xIncrement){ return X_LEFT + xIncrement * i; } private int getYCoordinate(int numStudents, int yIncrement){ return Y_BOTTOM - yIncrement * numStudents; } private int findLargest(int a[]){ int i; int loc = 0; for (i = 1; i < a.length; i++) if (a[i] > a[loc]) loc = i; return a[loc]; } private int sum(int a[]){ int i; int total= 0; for (i = 0; i < a.length; i++) total = total + a[i]; return total; } private Color intToColor(int i){ Color color = Color.black; switch (i){ case 0: color = Color.red; break; case 1: color = Color.green; break; case 2: color = Color.blue; break; case 3: color = Color.yellow; break; case 4: color = Color.magenta; break; } return color; } public static void main (String[] args){ Frame frm = new GraphTest(); frm.setSize (400, 300); frm.setVisible (true); } } |
| ||||