Chapter 9 - Graphics
Chapter 9 - Graphics
Graphics
Context
The purpose of this unit is to investigate Java's fundamental graphics methods, such as
the drawing of lines and shapes and the handling of fonts. The core Java ‘Graphics’
class that provides these facilities to a Java program is presented in particular detail.
Objectives
Implement Java applets that use graphics methods to draw shapes, text and
images
Use classes to simplify the display of complex and multiple shapes
Locate information about Java graphics classes in the on-line Javadoc
documentation
Study Planning
You should expect to spend approximately 9 hours studying this unit. You may find it
convenient to break up your study as follows:
Disk-based Content: 2¼
hours
Application: 3 hours
Set textbook Content: 1 hour
Reflection (On-line discussions, review 1 hour
questions):
Tutorial Work: 1 hour
Related Coursework: ¼ hour
Extension Work: ½ hour
Equipment/software required
1. Java: how to program. H. M. Deitel and P. J. Deitel, 3rd edition, Prentice-Hall, ISBN: 0-
13-012507-5
Online Resources:
1. Frequently-asked questions
2. Java 2D graphics overview on Sun's Java Web site
3. Additional Source Code Examples
Introduction to Unit 9
Read
The drawing of lines, points, images, text in various positions, sizes and colours
Colour control
Font control
Java includes support for these basic methods (covered in this unit), and a lot more
besides. More recent additions to the Java standard include the 'Java 2D' specification
(facilities to manipulate image by stretching, sizing and re-colouring) and 'Java 3D'
(facilities to render three-dimensional solid shapes on a two-dimensional screen).
Java graphics
Basic principles
Graphics methods are part of the AWT. Important AWT graphics classes include:
Graphics
Font
Color
Because a Java program may be sharing the computer screen with any number of other
programs, graphics methods are directed to specific AWT components. There is not,
nor should there ever be, any procedure to draw directly to the screen. This means that
when specifying the position of a shape or image, we specify it relative to the
component in which it is drawn.
In Java, as in most programming languages that support a graphical user interface, the
graphics methods are volatile (you will also see the term `non-persistent' used). This
means that the graphical information that is displayed on the screen will not be retained
if the program's display is over-written. This happens if, for example, your program is
hidden `behind' another program on the screen. When this happens, your program must
be ready to re-draw its display whenever it is `raised' to the top again.
Java makes this quite straightforward. Every user interface component has a method
called paint(). This method is called whenever the system detects that the
component needs to be re-painted. It is not the job of the programmer to manage the re-
painting of the screen.
‘Graphics’ class
Any AWT object can call getGraphics() to get a Graphics object. A Graphics object is
passed to the paint() method.
The Graphics class is very important in applications that draw graphical figures. It
contains a large number of methods for drawing lines, shapes, text, and images. In
addition, a Graphics object stores the current graphics context (described later in this
unit).
The most common way of using a Graphics object — one that you have seen already —
is to use the method paint() in an applet. The Java system automatically provides
a Graphics object to this method. The program can call any of the methods in the object
to do whatever drawing it needs. The paint() method is normally defined like this:
We don't have to call the object g (in fact, this is a rather meaningless name), but it has
become conventional to do so.
You will already have seen at least one method in the Graphics class:
thedrawString() method. This displays a String of text at a specific position.
Example of simple applet using object of graphics class
You will have seen many applets that use objects of the Graphics class. For example, a
Graphics object is the argument automatically passed to the applet when the system
invokes the paint() method.
import java.applet.Applet;
import java.awt.*;
} // class
Graphics context
stores the current drawing attributes: line colour, style, thickness, text font, etc
manages the co-ordinate system
The 'graphics context' is not exclusively a Java concept, but is important in most
computer systems that use a graphical user interface.
So if we wanted to draw three lines of text all in red, we would write something like this:
g.setColor (Color.red);
The first line sets the current colour to red, and the other lines all use that colour. If is
possible for two graphics contexts to be active in the same part of the display, each with
completely different attributes.
The other important feature of the graphics context is the management of the co-
ordinate system. This is described in more detail later.
Extending the previous example, we can create an applet to draw blue text in its window
to produce the following output:
import java.applet.Applet;
import java.awt.*;
public class DrawString2 extends Applet
{
} // class
Co-ordinates
To specify the position of something on a flat surface we need to give two numbers: the
horizontal distance from the origin and the vertical distance.
As can be see in the figure above, by default, the origin of the Java graphics co-ordinate
system is in the top-left corner of the object being drawn. This means that the position
specified when both numbers are zero is the top-left corner of the graphics context
(usually this is the same as the top-left corner of the component).
By convention we often refer to the horizontal position as the ‘x co-ordinate' and the
vertical position as the ‘y co-ordinate'.
Graphics primitives
'Primitives' are the basic shapes that can be drawn. In Java, facilities to draw primitive
shapes are provided in the Graphics class. The figure below shows the primitives that
are available, and the name of the method required to draw them.
To draw a complex shape that is not one of the primitives we have to combine primitives
until we get the shape we want.
import java.applet.Applet;
import java.awt.*;
To understand the fillRect() method of class Graphics, you can look up the relevant
entry in the Javadoc documentation — i.e.
Fonts
The font is the overall appearance and size of text. Java allows all components and
controls to select a different font if required. The program can also draw text on, say,
aCanvas object in any font. Java does not provide fonts; it only uses fonts provided by
the system the Java program is running on.
A Java user interface element that has text on it (e.g., Button, Label, Choice) can
display that text in any font. The component's setFont()method is used to select the
font that will be used.
When a program uses drawString() to write text on the screen, it is written in the
current font, whatever that happens to be. When the font is changed (for a
specificGraphics object), this affects all drawing methods on the same graphics object.
The method that selects the font in a Graphics object is also called setFont().
The fact that Java does not provide its own fonts means that the programmer has to be
rather careful in the choice of fonts if a program has to be truly portable. Even typefaces
that look very similar have different names on different platforms. For example, the
typeface called ‘helvetica' on Unix systems is very similar to ‘arial' on Windows systems,
but you would never guess from the names.
Note: terms like ‘font', ‘typeface', ‘style', ‘italic', etc., have very precise meanings in
typography, but they become very vague in the computer graphics field. Sadly, you will
see these terms used to mean a range of different things in different textbooks and
articles.
Font examples
Below are some examples of fonts in different typefaces, styles and sizes. Depending
on the size of the screen with which you are viewing this, the sizes may not be exactly
correct.
Java's font model is very simple (compared to that used by, for example, a
typographer).
The unit of size of text is the point. A 'point' is technically 1/72 of an imperial inch, so a
32-point font has characters that are nominally one half an inch high. In reality the
situation is more complicated than this, but since the characters that will displayed
depend on the screen size anyway, there's no point in being more accurate.
Note that when drawing text using Graphics.drawString(), the co-ordinates given
denote the left-hand end of the baseline of the text. The baseline is the lowest point of
most of the letters (like ‘ a’ , ‘ b’ , ‘ c’ ). Some letters (like ‘ q’ ) extend below the baseline;
you will need to take this into account when positioning text on the screen. For example,
if a program executes the line
g.drawString("abcdefg", 0, 0);
all that will be visible on the screen is the tail of the letter ‘g'.
This example creates a Label object, and assigns to it a plain Helvetica font of size 36
points (half an inch high).:
This example creates a font and enables it in the current graphics context. All
subsequent text methods will then use that font.
import java.applet.Applet;
import java.awt.*;
Java provides a method that will return a list of the fonts available for the system Java is
running on. A statement to invoke the method is as follows:
GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(
);
import java.applet.Applet;
import java.awt.*;
} // class
As can be seen in the code, a simple forloop is used (with a loop variablei) to retrieve
and display each of the String is in the array.
Images
An image is a file that represents an image using some standard grapichical image file
format (such as GIF and JPEG). Java's Graphics class can draw bitmapped images in
such file formats.
Images (from any source) are objects of class Image. The retrieval of an image may
take some time (e.g. from a distance web site), so it is carried out in the background.
The technicalities of retrieving and displaying an image are quite complex (involving
about six different classes) but this is mostly hidden from the programmer.
The method 'drawImage()' in the Graphics class draws an object of class Image on the
screen.
There are a variety of techniques for getting an Image object that represents a specific
image file. In a Java applet, the simplest technique is probably to use
the getImage()method in the Applet class. So displaying an image from a GIF file could
be as simple as this (in an applet):
g.drawImage(image, 0, 0, this);
Note that getImage() can retrieve images from a remote computer using a URL.
You may recall the Zener card images from a previous unit. Consider this output from a
simple applet:
import java.applet.Applet;
import java.awt.*;
g.drawImage(image, 0, 0, this);
} // class
In the applet above the 2-argument version of the method getImage() has been used.
Rather than getCodeBase(), we could have specified any URL for the directory where
the image file is located. The message getCodeBase() will result in the applet object
replying with the directory in which the " .class" object file is located.
Note that the image zenerWaves.gif is a GIF file that must be in the same directory
as the compiled applet ‘.class’ file, in order for this applet for successfully load and
display the image.
Colour
Colour is controlled by objects of Color class (note the US spelling). Colour is specified
as the level of red, green and blue, where each is between 0 and 255, or between 0 and
1. Not all displays can display all possible colours, and many are limited in the number
of simultaneous colours available. The display may use dithering to try to match the
requested colour, or may just use the closest colour available.
The methods setColor() and setBackground() in class Graphics are used to specify the
colours of any component. The arguments to these methods are objects of class colour.
When creating a new Color object, there are two ways to specify which colour to use:
g.setColor(new Color(Color.red));
In order to confuse the student, the levels of red, green and blue can be specified either
as numbers between 0 and 255, or between 0 and 1. In either case, 0 means ‘none of
that colour', while 1 or 255 means ‘this colour fully on'.
How does the Color object know whether we are using the range 0-1, or the range 0-
255?
If the numbers are floating point numbers (e.g., 1.0) then it will assume we are using the
0-1 range, and if they are integers (e.g., 1) it will assume the range is 0-255. If this were
not confusing enough, there is another method for specifying colours called the ‘sRGB'
standard which uses four numbers rather than three. Anyone interested should consult
the on-line documentation for full details.
Although most computer displays currently in use can display a wide range of colours,
many still limit the number of different colours that are available at one time. This is to
limit the amount of memory used to store the screen contents. For example, if we use 1
byte to store the colour of each screen pixel, then we will have 256 different colours
available (because one byte can store numbers between 0 and 255). The real colours
that these 256 numbers map on to is called the palette. Most displays will use one of
two methods if the program asks for a colour that is not currently part of the palette.
Either the nearest available colour will be used, or the display will use dithering to
synthesize the colour.
No-one can be expected to remember all the details of the Java standard
class library. Ensure that you can use the Java on-line documentation to find
details of the various classes. You will need to refer to this documentation
extensively in the following exercises.
Discussion of Activity 1
Start by opening in your browser the index.html file for the API javadocs. This is inside
the "api" folder where your JDK documents are located:
Once you have opened the api/index.html file your browser should present the normal
javadoc 3-frame layout:
From this window there are a number of ways to find the documentation for the
Graphics class. For example you could search for class Graphics in the lower left frame
(All Classes in alphabetical order). Alternatively you could choose the view the
complete Tree (hierarchy) of Java classes in the larger, right-hand frame. The
screenshot below illustrates both of these ways of locating the Graphics class
documentation:
Clicking on one of these Graphics links will take you to the Javadoc page on the
Graphics class. Scrolling down that page you can find out about each variable, method
and subclass:
Activity 2 — Find information about the Graphics class
The Graphics class contains many useful methods for drawing shapes and text. It is
important that you are able to find the documentation for this class and understand it.
Use the on-line documentation to find out the purpose and use of the
methodGraphics.clearRect().
Discussion of Activity 2
(1) Suppose a simple Java program draws a square whose centre is the centre of its
window. That is, if the window is 100 pixels wide and 100 pixels high, the centre of the
square and of the window is at position x=50, y=50.
If the square is exactly 50 pixels wide and 50 pixels high, what are the co-ordinates of
each of its four corners?
You may find it helps to draw the square and the window on paper first.
(2) write an applet to display a red square at these co-ordinates and with a side length
of 50.
Discussion of Activity 3
(1) There is only one 'right' answer to this exercise. The co-ordinates of the square are
shown in the diagram below. By convention the shorthand notation for a co-ordinate is
to write the x (across) co-ordinate first, then the y co-ordinate, separated by a comma.
So (20, 30) means ‘20 pixels across, 30 pixels down'.
(2) The code for an applet that would draw such a rectangle is as follows:
import java.applet.Applet;
import java.awt.*;
} // class
(of course, the size of the window can be changed by the user resizing it!).
If you want a Java program to draw a triangle (and triangle is not a primitive method in
the Graphics class), suggest two ways to do this using primitive shapes. Test both your
ideas using Java code.
Second method
Note that drawing the triangle starts and ends at the same point. This suggests that it
might be more elegant to use a polygon.
this has much less repetition, so is easier to modify and less likely to have bugs
introduced.
The full listing for an applet implementing the second method is as follows:
import java.applet.Applet;
import java.awt.*;
} // class
Activity 5 — Drawing a circle
Write an applet to draw a circle. The output from your applet should be similar to the
following:
Discussion of Activity 5
A circle is a type of oval (at least in Java it is. Mathematicians please don't write in). We
can draw a circle by drawing an oval whose height and width are the same, like this:
In this example the two 50s are the width and height. So long as these are equal we
have a circle.
import java.applet.Applet;
import java.awt.*;
}
} // class
Write a Java applet that displays the font typefaces available to a program. When the
user selects one of these typefaces, the program should display some text in that
typeface. The display should look something like this (the user has clicked on the name
'serif.bolditalic'):
This exercise has a number of tricky features. Here are a few hints to get you started
(you may also wish to refer back to the FontList.java applet mentioned in this units
Content section):
A Java program can get the list of available typefaces using the line
String listOfFonts[]
=GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamil
yNames();
This puts the list of typeface names into the String array listOfFonts[]. You can then
add these names to the font list (probably an object of class ‘List') using a for loop.
When the user selects an item in a List object, Java sends an event to the list's ‘item
listerner' (ItemListener ). The method addItemListener selects the object that will be
the item listener and therefore receive that event. Your applet itself can be the item
listener, by specifying ‘implements ItemListener' in the class
definition. ItemListener is defined injava.awt.event.ItemListener, so your program
will need to import this.
If you make the text display an object of class label, you can select its font easily by
using the ‘setFont()' method. If you do this, your applet probably won't need a paint
method.
You are also advised to look at the applet listing AccountChooser.java, which illustrates
how an array of Strings can be used to create a List component:
Discussion of Activity 6
A Java program must be able to re-draw its display completely whenever it is asked to
do so. It is a common mistakes made by novice programmers that the program looks
fine when it is first executed, but as time goes by bits of the display start to disappear.
This happens because the programmer has not provided the facilities to re-draw the
display on demand.
This seems a very complicated way of going about things. After all, the Java system
‘knows' when each component needs to be re-drawn; why can't it just ‘remember' what
is displayed in each component and display it when required? In addition, it takes time
for the Java program to re-draw the screen, and if it does so unnecessarily this is very
inefficient.
In fact there is a very good reason for Java to work this way. What would be the
problem with the Java system ‘remembering' the contents of each component, and
redrawing them automatically?
Discussion of Exercise 1
The problem with the Java system ‘remembering' the contents of each component is
that it may require a great deal of memory to do this. If there are many programs in use
at the same time, and most of them are hidden, there would be an awful lot of memory
in use just to keep track of the contents of the ‘invisible' parts of the display. Remember
that a computer uses three bytes of memory for each pixel in the display. If a Java
component is 500 pixels wide and 500 pixels high, this requires 500 x 500 x 3 bytes of
memory, which is nearly a megabyte. If the computer is executing ten programs
simultaneously, then perhaps 25% of its total memory capacity could be taken up just
with ‘remembering' screen contents.
In practice, as memory become cheaper and computers often have more than 128 Mb
of RAM fitter, this issue is becoming less important.
Review Questions
Review Question 1
Java programs can draw directly onto Frames — is this a good idea, and what else can
they draw onto?
Review Question 1
However, this is not recommended — it is best to draw onto a Panel or Canvas object.
Review Question 2
In simple applets, so far we have used the applet's ‘paint()' method to display text or
graphics in the applet. However, in this unit we said that this was a bad idea. Rather
than displaying graphics directly on an applet, it was suggested that you should create a
new object and place this in an applet. For example, we could create a new object
which is a subclass of Canvas (a blank area of screen) and use its paint method to do
the drawing. This object could then be inserted in the applet using ‘add'. A skeleton of a
program that works this way may look something like this:
public MyApplet()
// the applet
add(new Drawing());
class Drawing
}
So in this example, all the drawing methods are in the class Drawing and the applet
itself has no graphics methods.
This approach leads to a longer program, and it is more complex (at least superficially).
So what are the advantages of this programming strategy?
Review Question 2
If we draw directly in the applet's paint method, then it will become impossible to
disentangle the drawing methods from other things the applet might do (like handling
menus and mouse clicks). The use of a separate class means that these drawing
methods are separate from other things the program might do; this makes the program
easier to modify, maintain and test.
If the drawing is done in a separate class, it is easier to re-use those drawing facilities in
a different program. For example, many programs display the current time at some
place on the screen. If the instructions to do this are encapsulated in a separate class, it
is easy to use that class again in a different program. In Java the instructions to display
a button are contained in the Button class, a menu in the Menu class, etc.
Discussion Topics
The use of fonts is a bit of a headache for programming languages that are designed to
encourage portability. If a program asks for a display in a given typeface, and that
typeface is not available on a particular computer, clearly there is a problem. What
options could Java take if a program requests a font that does not exist? For example,
suppose we have the line
and there is no font called ‘no_such_font'? If you have finished exercise 5 (the font list
applet) you should have noticed one way in which the impact of this problem is being
reduced.
What is it, and do you think it is successful? What disadvantages are there to this
approach?
Contribution for Discussion Topic 1 – Unavailable font resolution
If Java can find no such font, then the Font object is set to a default (the font of the
parent).
Alternative actions that the Java developers could have chosen are for a run-time
exception to occur, which the programmer would need to catch and deal with, or allow
run-time exception messages to be displayed. However, since there is a default font
that is inherited, they appear to have decided that this is not a case where an exception
is warranted.
Discussion Topic 2 — Graphics primitives?
Are the graphics primitives provided by the Graphics class really primitive?
Why do you think the Java developers picked these shapes as being primitive?
Graphics primitives?
The primitives provided at first seem primitive - lines, ovals, filled rectangles etc. In fact
these are relatively sophisticated methods, since they need to implement line drawing,
curve drawing and object filling algorithms.
The dots on a screen are discrete, so there is not an obviously correct way to decide
which pixels should be lit to create a straight (or curved) line between two points. You
might like to find out more about these issues from any introduction to 2D graphics.
The reason to choose the particular set of primitives provided by Java is that they are
sufficient to build almost all other shapes — so polylines and arcs can be used to create
curves that deviate from part of an oval or circle. Polygons can be used to represent any
straight-edged objects etc.
In your Learning Journal write up your experience of your learning on this unit. Say what
you thought was good or bad, what you had difficulty understanding, and how you
resolved your problems.
Destructor methods
Objects can be created and destroyed by programs. Part of a class definition can be a
method, called a destructor, that is executed when the object is to be destroyed. In Java
such a method must have the identifier finalise, and an example might be:
This particular destructor method is not very useful, however, it illustrates that it is
possible to add a destructor method to classes, so that actions can be performed by an
object being destroyed.