Drawing Shapes: Application
Drawing Shapes: Application
27
Objectives
In this tutorial, you will learn to:
Drawing Shapes
■ Use polymorphism to create
an application that process
related objects as though
Application
they are the same.
■ Use additional Graphics Introduction to Polymorphism; an
methods such as drawLine.
■ Create an application that
Expanded Discussion of Graphics
allows users to draw shapes.
27.2
Shapes Application
Polymorphism
P to “program in the general” rather than having to “program in the specific.”
In particular, polymorphism makes it easy to write code to process a variety
of related objects. The same method call is made on these objects and each of the
27.3 More Graphics Methods objects will “do the right thing.” If, for example, you ask an object to “talk” it will
27.4 Adding to the MyShape respond appropriately. If you tell a pig object to talk, it will respond with an
Inheritance Hierarchy “oink.” If you tell a dog object to talk, it will respond with a “bark.”
27.5 Wrap-Up Polymorphic applications handle, in a simple and convenient manner, objects
of many classes that belong to the same inheritance hierarchy. These applications
focus on the similarities between these classes rather than the differences.
With polymorphism, it is also possible to design and implement systems that
are easily extended with new capabilities. New classes can be added with little or
no modification to the rest of the application, as long as those classes share the
similarities of the classes that the application already processes. These new
classes simply “plug right in.”
In this tutorial, you will add polymorphic processing to the Drawing Shapes
application. You will also learn additional methods of the Graphics class to out-
line and fill in different types of shapes.
787
788 Introduction to Polymorphism; an Expanded Discussion of Graphics Tutorial 27
This application allows a user to draw three different kinds of shapes in a vari-
ety of colors. The user chooses the shape and color, then presses a mouse button
and drags the mouse to create the shape. The user can draw as many shapes as
desired. You begin by test-driving the completed application. Then, you will learn
the additional Java technologies you will need to create your own version of this
application.
Test-Driving the Drawing 1. Locating the completed application. Open the Command Prompt window
Shapes Application by selecting Start > Programs > Accessories > Command Prompt.
Change to your completed Drawing Shapes application directory by typing
cd C:\Examples\Tutorial27\CompletedApplication\DrawingShapes.
2. Running the Drawing Shapes application. Type java DrawingShapes in
the Command Prompt window to run the application (Fig. 27.1).
Drawing area
3. Changing the type of shape to draw. Click the JComboBox at the top of the
application and select Oval (Fig. 27.2).
(cont.) 4. Changing the color of the shape to be drawn. Click the Color JButton at
the top of the application. This will open the JColorChooser dialog which
allows you to select a color for the shapes you will draw. The JColor-
Chooser dialog will look identical to Fig. 22.3. Select a color and click the
OK JButton in the JColorChooser dialog. Notice that when you select a
new color, the color of the Color JButton changes to the newly selected
color.
5. Drawing an oval. Once you have chosen a shape to draw and a color for
your shape, move your mouse pointer to the drawing area (the white rectan-
gle). Click and hold the left mouse button to create a new shape. One end of
the shape will be positioned at the mouse cursor. Drag the mouse around to
position the opposite end of the shape at the location you desire, then
release the mouse.
27.2 Polymorphism
You will now continue your study of object-oriented programming by learning
about polymorphism with inheritance hierarchies. With polymorphism, the same
method signature can be used to cause different actions to occur, depending on the
type of the object on which the method is invoked.
As an example, suppose you design a video game that manipulates objects of
many different types, including objects of classes Bird, Fish and Snake. Also, imag-
ine that each of these classes inherits from a common superclass called Animal,
which contains method move. Each subclass implements this method. Your video
game application would maintain a collection (such as an ArrayList) of references
to objects of the various classes. To move the animals, the application would period-
ically send each object the same message—namely move. Each object responds to
this message in a unique way. For example, a Bird flies across the screen. A Fish
swims through a lake. A Snake slithers through the grass. The same message (in this
case, move) sent to a variety of objects would have “many forms” of results—hence
the term polymorphism which means literally “many forms”.
Consider another example—developing a simple payroll system for an
Employee inheritance hierarchy. Every Employee has an earnings method that
calculates the employee’s weekly pay. These earnings methods vary by employee
type—a SalariedEmployee is paid a fixed weekly salary regardless of the number
of hours worked. An HourlyEmployee is paid by the hour and receives overtime
pay. A CommissionEmployee receives a percentage of sales. The same message (in
this case, earnings) sent to a variety of objects would have “many forms” of
results—again, polymorphism.
For the Drawing Shapes application, you will develop a simple inheritance
hierarchy. The MyShape class will declare the basic properties of a shape such as its
color and location. Three other classes will extend MyShape and each of these
classes will declare more specific shape information. These classes are MyLine,
MyRectangle and MyOval. The UML class diagram of Fig. 27.4 demonstrates the
inheritance hierarchy for your Drawing Shapes application.
MyShape
Figure 27.4 UML class diagram for the inheritance hierarchy in the Drawing Shapes
application.
Calling the draw method on a MyLine object draws a line. Calling the draw
method on a MyRectangle object draws a rectangle. [Note: The MyOval class is not
included in the template application. You will declare it later in this tutorial.] The
same message (in this case, draw) sent to a variety of objects would have “many
forms” of results—again, polymorphism.
Now that you have test-driven the Drawing Shapes application and studied its
pseudocode representation, you will use an ACE table to help you convert the
pseudocode to Java. Figure 27.5 lists the actions, components and events that will
help you complete your own version of the application.
When you think of a class type, you assume that applications will create objects
of that type. However, there are cases in which it is useful to declare classes for
which the programmer never intends to instantiate objects. Such classes are called
abstract classes. Because abstract classes are used only as superclasses in inherit-
ance hierarchies, those classes are often called abstract superclasses. These classes
cannot be used to instantiate objects, because, as you will see, abstract classes are
incomplete. Subclasses must declare the “missing pieces.” Abstract superclasses are
often used in polymorphic applications which is why polymorphism is sometimes
called programming “in the abstract.”
The purpose of an abstract class is to provide an appropriate superclass from
which other classes can inherit. Classes that can be used to instantiate objects are
called concrete classes. Abstract superclasses are too generic to create real
objects—they specify only what is common among their subclasses. You need to be
more specific before you can create objects. Concrete classes provide the specifics
that make it possible to instantiate objects.
In the MyShape inheritance hierarchy described previously, MyShape is an
abstract superclass. It declares a draw method, but does not provide an implemen-
tation of that method. If someone tells you to “draw the shape,” your response
would likely be “what shape should I draw?” This draw method is the missing piece
that makes it impossible to instantiate a MyShape object. If instead you were told to
“draw a line” or “draw a rectangle,” you could do so. The MyLine class is a concrete
subclass of MyShape because the MyLine class includes an implementation of the
draw method which specifically draws a line. The MyRectangle class is a concrete
subclass of MyShape because the MyRectangle class includes an implementation of
the draw method which specifically draws a rectangle.
You will finish the MyShape inheritance hierarchy by declaring the MyShape
class abstract and adding a draw method. You will then provide an implementa-
tion of the draw method in classes MyLine and MyRectangle.
Declaring an abstract 1. Copying the template to your working directory. Copy the C:\Examples\
Method Tutorial27\TemplateApplication\DrawingShapes directory to your
C:\SimplyJava directory.
2. Opening the MyShape template file. Open the template file MyShape.java
in your text editor.
3. Declaring the MyShape class abstract. Modify line 5 as shown in Fig. 27.6.
This line declares the MyShape class abstract. By declaring this class
abstract, instances of this class cannot be created. In this application, you
will create instances of MyShape’s subclasses—MyLine, MyRectangle and
MyOval.
4. Declaring an abstract method. Insert lines 95–96 of Fig. 27.7 after method
getColor. These lines declare abstract method draw, but provide no imple-
mentation for it. Abstract methods are declared by writing a method header
followed by a semicolon—no method body is provided. This draw method is
the missing piece of the MyShape class that makes it impossible to instantiate.
If any method in a class is declared abstract, then the whole class must be
declared abstract (as you did in the previous step). The concrete subclasses
of MyShape must provide an implementation of the draw method.
Tutorial 27 Drawing Shapes Application 793
(cont.)
Declaring abstract
method draw
In Tutorial 20, you learned to set the color of drawn shapes using the setColor
method and to draw a filled rectangle using the fillRect method. In Tutorial 21,
you learned to draw a filled oval using the fillOval method. Each of these meth-
ods belongs to class Graphics. Now, you will learn about Graphics methods for
drawing lines, rectangles and ovals. Figure 27.8 summarizes the Graphics methods
you have learned and introduces several new ones.
Figure 27.8 Graphics methods that draw lines, rectangles and ovals.
The MyLine class extends the abstract class MyShape which contains
abstract method draw. To declare MyLine as a concrete subclass, you must pro-
vide an implementation for the draw method. If you extend an abstract super-
class, you must provide an implementation for each of its abstract methods or else
the subclass must be declared abstract as well.
You will now provide an implementation of the draw method in the MyLine
class. This method should draw a line starting at one of the endpoints specified in
the MyLine object and ending at the other one.
Implementing the draw 1. Opening the MyLine template file. Open the template file MyLine.java in
Method in Class MyLine your text editor.
2. Implementing the draw method in the MyLine class. Insert lines 18–19 of
Fig. 27.9 into the draw method. Line 18 calls method getColor to get the
color of the MyShape. The return value is passed to method setColor to set
the color of the Graphics object (g) for drawing. Line 19 calls the drawLine
method on the Graphics object. This method takes four int values; the first
two are the x- and y-coordinates of the first endpoint of the line and the sec-
ond two are the x- and y-coordinates of the second endpoint of the line.
794 Introduction to Polymorphism; an Expanded Discussion of Graphics Tutorial 27
(cont.)
Your application receives input from the user in the form of two points on the
screen—the location at which the user originally clicks the mouse button and the
location to which the user drags the mouse cursor. Drawing a line between these
two points is simple; the drawLine method of class Graphics takes the location of
two points as arguments. Drawing a rectangle based on these two points is more
complicated though. The drawn rectangle will have one corner located at one of the
points and the diagonally opposite, corner located on the other point. In the
MyRectangle class’s draw method, you will need to use these two points to calcu-
late the x- and y-coordinates of the upper-left corner of the rectangle along with the
rectangle’s width and height.
You will now implement the draw method in the MyRectangle class to make
MyRectangle a concrete subclass of MyShape. This method should draw a rectangle
on the screen with one corner at one point of the MyRectangle object and the
opposite corner at the other point.
Implementing the draw 1. Opening the MyRectangle template file. Open the template file MyRectan-
Method in Class gle.java in your text editor.
MyRectangle 2. Calculating the coordinates of the upper-left corner. Insert lines 18–19 of
Fig. 27.10 into the draw method. As you learned in Tutorial 20, the fill-
Rect method takes as arguments the x- and y-coordinates of the upper-left
point of the rectangle along with the width and the height. The MyRectangle
class stores its data in instance variables x1, x2, y1 and y2. Your draw
method will need to convert the information stored in the MyRectangle
class to the correct information to pass to the fillRect method.
Line 18 uses the Math class’s min method to determine the smaller of the
two x-coordinates, which is the one farther left. This method call returns the
left edge of the rectangle. Line 19 calls the min method to determine the
smaller of the two y-coordinates, which is the one higher than the other. This
method call returns the top of the rectangle.
(cont.) 3. Calculating the width and height. Insert lines 20–24 of Fig. 27.11 into your
code. The abs method of class Math returns the absolute value (the value of
the number without the sign of the number) of the expression it receives.
Line 20 uses the abs method to determine the difference between the two x-
coordinates, which is the width of the rectangle. Line 21 uses the Math class’s
abs method to determine the difference between the two y-coordinates,
which is the height of the rectangle. Line 23 sets the color of the rectangle.
Line 24 calls method fillRect using the x- and y-coordinates that you cal-
culated in the previous step, along with the width and height that you calcu-
lated in this step.
Figure 27.11 Calculating the width and height and drawing the rectangle.
You will now finish the PaintJPanel class to allow the user to create and resize
shapes.
Finishing the 1. Opening the template file. Open the template file PaintJPanel.java in
PaintJPanel Class your text editor.
2. Declaring a MyShape instance variable. Add lines 13–14 of Fig. 27.12 into
your code. These lines declare a MyShape instance variable to hold the cur-
rent shape. The MyShape class is an abstract class and cannot be instanti-
ated, but references of the MyShape class can be created. This is one of the
keys to polymorphism. This reference is used to resize a shape after it has
been created. With polymorphism, you do not need to know what type of
shape is stored in the MyShape reference.
Declaring a myShape
instance variable
3. Creating a new MyLine object. Insert lines 72–77 of Fig. 27.13 into method
paintJPanelMousePressed. Line 73 tests whether the user selected Line in
the JComboBox. If this is the case, lines 75–76 create a new MyLine object.
These lines use methods getX and getY of MouseEvent to determine where
the mouse is positioned. This MyLine object is created with the first endpoint
the same as the second endpoint. This makes the length of the line 0 and it
appears as a single colored pixel. When the user drags the mouse, the second
endpoint will be repositioned, changing the size of the line.
796 Introduction to Polymorphism; an Expanded Discussion of Graphics Tutorial 27
(cont.)
4. Creating a new MyRectangle object. Insert lines 78–83 of Fig. 27.14 into
method paintJPanelMousePressed. Line 79 tests whether the user
selected Rectangle in the JComboBox. If this is the case, lines 81–82 create
a new MyRectangle object. These lines use methods getX and getY of
MouseEvent to determine where the mouse is positioned. This MyRectan-
gle object is created with the first endpoint the same as the second end-
point. This makes the rectangle appear as a single colored pixel. When the
user drags the mouse, the second endpoint will be repositioned, changing
the size and shape of the rectangle.
6. Resizing the shape. Add lines 92–94 of Fig. 27.16 to method paintJPanel-
MouseDragged. When the user drags the mouse, currentShape must be
resized. Lines 92–93 resize the shape by changing the x- and y-coordinates
of the shape’s second point. Recall that when the shape is constructed, the
first and second points are at the same location. Changing the location of
the second point resizes the shape, while keeping the first point in place.
These lines use MouseEvent methods getX and getY to get the location of
the mouse cursor.
Tutorial 27 Drawing Shapes Application 797
(cont.) Lines 92–93 use the MyShape variable currentShape without knowing
exactly what type of shape is being affected. This is an example of polymor-
phic processing. The calls to methods setX2 and setY2 are allowed because
these methods are declared in the MyShape class. All classes that extend
MyShape contain these methods. Line 94 calls the repaint method, which
will call the paintComponent method which you will declare next.
7. Paint all the shapes. Add lines 103–112 of Fig. 27.17 to method paintCom-
ponent. Line 104 creates an Iterator to traverse through each element of
shapesArrayList. Lines 107–112 iterate through the items in shapes-
ArrayList. Line 110 calls method next to get a reference to the next object
in shapesArrayList. This method returns an instance of type Object which
is then cast to a MyShape reference and assigned to nextShape. Line 111
calls method draw on nextShape.
At this point, you do not know which draw method will be called—the
one in MyLine or the one in MyRectangle. The method call will be resolved
only when the application is executed. Each shape in shapesArrayList
knows how to draw itself. If nextShape is a MyLine object, the draw method
from the MyLine class will be called. If nextShape is instead a MyRectangle
object, the draw method from the MyRectangle class will be called.
You have now finished coding the PaintJPanel class. Next, you will instantiate
an object of PaintJPanel and use it in your Drawing Shapes application to allow
the user to draw shapes.
Adding a PaintJPanel 1. Opening the template file. Open the template file DrawingShapes.java in
to Your Application your text editor.
2. Declaring a PaintJPanel instance variable. Add lines 19–20 of Fig. 27.18
to your code to declare a PaintJPanel instance variable. This PaintJPanel
component listens for mouse events and uses them to draw shapes.
798 Introduction to Polymorphism; an Expanded Discussion of Graphics Tutorial 27
(cont.)
Declaring a PaintJPanel
instance variable
3. Creating and customizing the PaintJPanel. Add lines 46–50 of Fig. 27.19
to your application. Line 47 instantiates a PaintJPanel object named
painterPaintJPanel. Lines 48–49 set the bounds and background prop-
erties for the painterPaintJPanel, respectively. Line 50 adds painter-
PaintJPanel to the content pane to display the component and allow the
user to interact with it.
4. Setting the color for the next drawn MyShape. Add line 105 of Fig. 27.20 to
method colorJButtonActionPerformed. This line sets the color of the
shape to be drawn to the color the user selected in the JColorChooser dia-
log. Now, when the user selects a color, that color will be set as the current
color of painterPaintJPanel.
5. Setting the type of the drawn MyShape. Add lines 113–114 of Fig. 27.21 to
method shapeJComboBoxActionPerformed. These lines take the name of
the shape that the user selected from shapeJComboBox and pass it to pain-
terPaintJPanel. The getSelectedItem method returns the Object that
is currently selected in shapeJComboBox, which is then cast to String and
passed to method setCurrentShapeType of PaintJPanel. When the user
drags the mouse on painterPaintJPanel, a shape of the user’s selected
type and color will appear.
(cont.) 7. Opening the Command Prompt window and changing directories. Open
the Command Prompt window by selecting Start > Programs > Accesso-
ries > Command Prompt. Change to your working directory by typing cd
C:\SimplyJava\DrawingShapes.
8. Compiling the application. Compile your application by typing javac
DrawingShapes.java PaintJPanel.java MyShape.java MyLine.java
MyRectangle.java.
9. Running the application. When your application compiles correctly, run it
by typing java DrawingShapes. Figure 27.28 shows the completed applica-
tion running. Users can now select and draw a line or a rectangle, but cannot
select or draw an oval.
10. Closing the application. Close your running application by clicking its close
button.
11. Closing the Command Prompt window. Close the Command Prompt win-
dow by clicking its close button.
Adding Class MyOval to 1. Create the MyOval file. Create a new source code file. Name this new file
the Inheritance MyOval.java. After you have created the file, open it in your text editor.
Hierarchy 2. Declare the MyOval class. Add lines 1–8 of Fig. 27.23 to MyOval.java. Line
5 declares that class MyOval extends class MyShape. The class declaration
ends with the right brace on line 8.
3. Adding a constructor. Add lines 7–13 of Fig. 27.24 to the class declaration.
These lines declare a constructor for MyOval which takes four integer argu-
ments and a Color argument. This constructor calls the superclass’s con-
structor which also takes four int arguments and a Color argument.
4. Implementing the draw method. Add lines 15–26 of Fig. 27.25 after the con-
structor. These lines implement the draw method declared in class MyShape
to draw an oval. Lines 18–21 calculate the dimensions of the oval to be
drawn. These calculations are the same as those that were required for the
MyRectangle class. Recall that the min method returns the smallest of the
two values it receives and the abs method returns the absolute value of the
expression it receives. Line 24 calls Graphics method fillOval to draw an
oval in the application.
Now that you have created class MyOval, you must modify some of the code in
the application. First, you must add an option to the JComboBox allowing the user to
select an oval to draw.
Allowing the User to 1. Opening the template file. Open the template file DrawingShapes.java in
Draw an Oval your text editor.
2. Adding an oval option to the JComboBox. Modify line 23 of your source
code file so it looks like line 23 of Fig. 27.26. This adds an “Oval” option to
the JComboBox which allows the user to select an oval as the shape to draw.
Figure 27.26 Adding the oval option to the String array shapeTypes.
The user can now select an oval, but the application must also create a MyOval
object.
Creating a MyOval 1. Opening the template file. Open the template file PaintJPanel.java in
Object your text editor.
2. Creating a MyOval object. Add lines 84–89 of Fig. 27.27 to method paintJ-
PanelMousePressed. Line 85 tests whether the current shape type is equal
to "Oval". If it is, lines 87–88 create a new MyOval object.
Notice that you do not need to make any changes to the method that
resizes the shape (paintJPanelMouseDragged) or the method that draws
the shape (paintComponent) because they handle the shapes polymorphi-
cally. Line 111 of Fig. 27.17 calls the draw method on MyShape reference
currentShape. If currentShape actually refers to a MyOval object, the
draw method declared in the MyOval class is called. The MyOval object
knows how to draw itself.
3. Saving the application. Save your modified source code file.
4. Opening the Command Prompt window and changing directories. Open
the Command Prompt window by selecting Start > Programs > Accesso-
ries > Command Prompt. Change to your working directory by typing cd
C:\SimplyJava\DrawingShapes.
5. Compiling the application. Compile your application by typing javac
DrawingShapes.java PaintJPanel.java MyOval.java.
802 Introduction to Polymorphism; an Expanded Discussion of Graphics Tutorial 27
(cont.) 6. Running the application. When your application compiles correctly, run it
by typing java DrawingShapes. Figure 27.28 shows the completed applica-
tion running. Users can now select and draw an oval.
7. Closing the application. Close your running application by clicking its close
button.
8. Closing the Command Prompt window. Close the Command Prompt win-
dow by clicking its close button.
Figure 27.29–Fig. 27.30 present the source code for the Drawing Shapes appli-
cation. The lines of code that you added, viewed or modified in this tutorial are
highlighted.
25 // no-argument constructor
26 public DrawingShapes()
27 {
28 createUserInterface();
29 }
30
31 // create and position GUI components; register event handlers
32 private void createUserInterface()
33 {
34 // get content pane for attaching GUI components
35 Container contentPane = getContentPane();
36
37 // enable explicit positioning of GUI components
38 contentPane.setLayout( null );
39
40 // set up controlsJPanel
41 controlsJPanel = new JPanel();
42 controlsJPanel.setBounds( 0, 0, 400, 40 );
43 controlsJPanel.setLayout( null );
44 contentPane.add( controlsJPanel );
45
46 // set up painterPaintJPanel
47 painterPaintJPanel = new PaintJPanel();
48 painterPaintJPanel.setBounds( 0, 40, 400, 340 );
49 painterPaintJPanel.setBackground( Color.WHITE );
50 contentPane.add( painterPaintJPanel );
51
52 // set up shapeJComboBox
53 shapeJComboBox = new JComboBox( shapeTypes );
54 shapeJComboBox.setBounds( 90, 2, 100, 24 );
55 controlsJPanel.add( shapeJComboBox );
56 shapeJComboBox.addActionListener(
57
58 new ActionListener() // anonymous inner class
59 {
60 // event method called when shapeJComboBox is selected
61 public void actionPerformed( ActionEvent event )
62 {
63 shapeJComboBoxActionPerformed( event );
64 }
65
66 } // end anonymous inner class
67
68 ); // end call to addActionListener
69
70 // set up colorJButton
71 colorJButton = new JButton();
72 colorJButton.setBounds( 210, 2, 80, 24 );
73 colorJButton.setText( "Color" );
74 controlsJPanel.add( colorJButton );
75 colorJButton.addActionListener(
76
77 new ActionListener() // anonymous inner class
78 {
79 // event handler called when colorJButton is pressed
80 public void actionPerformed( ActionEvent event )
81 {
82 colorJButtonActionPerformed( event );
83 }
84
85 } // end anonymous inner class
86
87 ); // end call to addActionListener
88
89 // set properties of application’s window
90 setTitle( "Drawing Shapes" ); // set title bar string
91 setSize( 408, 407 ); // set window size
92 setVisible( true ); // display window
93
94 } // end method createUserInterface
95
96 // select a new color for the shape
97 private void colorJButtonActionPerformed( ActionEvent event )
98 {
99 Color selection = JColorChooser.showDialog( null,
100 "Select a Color", Color.BLACK );
101
102 if ( selection != null )
103 {
104 colorJButton.setBackground( selection );
Setting the color of
105 painterPaintJPanel.setCurrentColor( selection );
the PaintJPanel
106 }
107
108 } // end method colorJButtonActionPerformed
109
110 // set the selected shape in the painting panel
111 private void shapeJComboBoxActionPerformed( ActionEvent event )
112 {
113 painterPaintJPanel.setCurrentShapeType(
Setting the shape to draw
114 ( String )shapeJComboBox.getSelectedItem() );
115
116 } // end method shapeJComboBoxActionPerformed
117
118 // main method
119 public static void main( String args[] )
120 {
121 DrawingShapes application = new DrawingShapes();
122 application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
123
124 } // end method main
125
126 } // end class DrawingShapes
12
13 // current shape that is being drawn
14 private MyShape currentShape;
15
16 // currently selected shape type
17 private String currentType = "Line";
18
19 // currently selected color
20 private Color currentColor = new Color( 204, 204, 204 );
21
22 // no-argument constructor
23 public PaintJPanel()
24 {
25 addMouseListener(
26
27 new MouseAdapter() // anonymous inner class
28 {
29 // event handler called when mouse button is pressed
30 public void mousePressed( MouseEvent event )
31 {
32 paintJPanelMousePressed( event );
33 }
34
35 } // end anonymous inner class
36
37 ); // end call to addMouseListener
38
39 addMouseMotionListener(
40
41 new MouseMotionAdapter() // anonymous inner class
42 {
43 // event handler called when the mouse is dragged
44 public void mouseDragged( MouseEvent event )
45 {
46 paintJPanelMouseDragged( event );
47 }
48
49 } // end anonymous inner class
50
51 ); // end call to addMouseMotionListener
52
53 } // end constructor
54
55 // change the current shape type
56 public void setCurrentShapeType( String shape )
57 {
58 currentType = shape;
59
60 } // end method setCurrentShapeType
61
62 // change the current color
63 public void setCurrentColor( Color shapeColor )
64 {
65 currentColor = shapeColor;
66
67 } // end method setCurrentColor
68
59
60 // get x2 value
61 public int getX2()
62 {
63 return x2;
64
65 } // end method getX2
66
67 // set y2 value
68 public void setY2( int y )
69 {
70 y2 = y;
71
72 } // end method setY2
73
74 // get y2 value
75 public int getY2()
76 {
77 return y2;
78
79 } // end method getY2
80
81 // set color value
82 public void setColor( Color c )
83 {
84 color = c;
85
86 } // end method setColor
87
88 // get color value
89 public Color getColor()
90 {
91 return color;
92
93 } // end method getColor
94
95 // abstract draw method
Declaring abstract
96 public abstract void draw( Graphics g );
method draw
97
98 } // end class MyShape
15 // draw a line
16 public void draw( Graphics g )
17 {
Implementing the abstract 18 g.setColor( getColor() );
draw method from MyShape 19 g.drawLine( getX1(), getY1(), getX2(), getY2() );
20
21 } // end method draw
22
23 } // end class MyLine
15 // draw an oval
Implementing the abstract
draw method from MyShape
16 public void draw( Graphics g )
17 {
18 int upperLeftX = Math.min( getX1(), getX2() );
Calculating the x- and y-
19 int upperLeftY = Math.min( getY1(), getY2() );
coordinates, width and height
20 int width = Math.abs( getX1() - getX2() );
of the rectangle
21 int height = Math.abs( getY1() - getY2() );
22
23 g.setColor( getColor() );
24 g.fillOval( upperLeftX, upperLeftY, width, height );
25
26 } // end method draw
27
28 } // end class MyOval
Answers: 1) b. 2) b.
27.5 Wrap-Up
In this tutorial, you learned about polymorphism. You created a Drawing Shapes
application, which allows you to draw a picture by combining different colored
shapes. You learned how to use additional Graphics methods to draw a line, a
filled rectangle and a filled oval.
While building the Drawing Shapes application, you used an inheritance hier-
archy consisting of the MyShape superclass and the MyLine, MyRectangle and MyO-
val subclasses. You also handled objects of the three subclasses polymorphically—
by treating them as objects of the MyShape superclass.
In the next tutorial, you will learn about the Java Speech API which produces
synthetic speech from text input. You will use this technology to create a phone
book application that will speak a selected person’s phone number.
KEY TERMS abs method of the Math class—Returns the absolute value of a given value.
absolute value—The value of a number without the sign of the number.
Tutorial 27 Drawing Shapes Application 811
abstract class—A class that cannot be instantiated. Often called an abstract superclass
because it is usable only as the superclass in an inheritance hierarchy. These classes are
incomplete; they are missing pieces necessary for instantiation which concrete subclasses
must implement.
abstract keyword—Used to declare that a class or method is abstract.
abstract method—Contains a method header but no method body. Any class with an abstract
method must be an abstract class.
concrete class—A class that can be instantiated.
drawLine method of the Graphics class—Draws a line using the given x- and y-coordinates.
drawOval method of the Graphics class—Draws an oval using the bounding box’s upper-left
x- and y-coordinates and the width and height.
drawRect method of the Graphics class—Draws a rectangle using the given x- and y-coordi-
nates and the rectangle’s width and height.
min method of the Math class—Returns the minimum of two values.
polymorphism—Concept that allows you to write applications that handle, in a more general
manner, a wide variety of classes related by inheritance.
JAVA LIBRARY Graphics The Graphics class provides methods to draw shapes of varying colors.
■ Methods
REFERENCE
drawLine—Takes four arguments and draws a line at the specified beginning and ending
x- and y-coordinates.
drawOval—Takes four arguments and draws an unfilled oval inside a bounding rectangu-
lar area. The first two arguments are the x- and y-coordinates of the top-left corner of
the rectangular area and the second two are the width and height.
drawRect—Takes four arguments and draws an unfilled rectangle at the specified upper-
left x- and y-coordinates and of the specified width and height.
fillRect—Takes four arguments and draws a solid rectangle at the specified upper-left
x- and y-coordinates and of the specified width and height.
fillOval—Takes four arguments and draws a solid oval inside a bounding rectangular
area. The first two arguments are the x- and y-coordinates of the top-left corner of
the rectangular area and the second two are the width and height.
setColor—Sets the color of the Graphics object.
Math The Math class provides methods to perform different mathematical functions.
■ Methods
abs—Returns the absolute value of its argument.
max—Returns the greater of its two arguments.
min—Returns the lesser of its two arguments.
27.2 Because of polymorphism, using the same can cause different actions to
occur depending on the type of the object on which a method is invoked.
a) method return type b) instance variable
c) local variable d) method signature
27.3 The method returns the absolute value of a number.
a) abs b) absolute
c) positive d) positiveValue
812 Introduction to Polymorphism; an Expanded Discussion of Graphics Tutorial 27
EXERCISES 27.11 (Advanced Screen Saver Application) Write an application that mimics the behavior
of a screen saver. It should draw random shapes onto a black background and the shapes
should build up on top of each other until the screen saver resets (every 30 seconds). You
have been provided with a Screen Saver application that does not yet display outlined
shapes. It uses the MyRectangle and MyOval classes that you created in this tutorial. Add the
code that will display random outlined shapes in your output. Your output should look like
Fig. 27.35.
a) Copying the template to your working directory. Copy the directory C:\Examples\
Tutorial27\Exercises\AdvancedScreenSaver to your C:\SimplyJava directory.
b) Opening the template file. Open the MyRectangle.java file in your text editor.
c) Adding an instance variable to the MyRectangle class. At line 7, add a comment
indicating that the instance variable is a boolean and will indicate whether or not the
rectangle is filled. At line 8, add a private instance variable named filled of type
boolean.
d) Modifying the MyRectangle constructor. You will now modify the MyRectangle
constructor so that it can accept an additional boolean argument. At line 12, add a
boolean argument named fill to the end of the parameter list. At line 16, set the
instance variable filled equal to the value of parameter fill and on the same line,
add a comment indicating that filled will specify if the shape will be filled.
e) Modifying the draw method. At line 31, add comment indicating that an if state-
ment will execute if the rectangle is filled. At line 32, add an if statement that checks
if filled is true. If it is, then the application should call the fillRect method
(which is on line 30 of the template).
Tutorial 27 Drawing Shapes Application 813
f) Finishing the draw method. At line 37, add an else to the if statement from the pre-
vious step. If filled is false, the application should call the drawRect method.
g) Saving the application. Save your modified source code file.
h) Opening the template file. Open the MyOval.java file in your text editor.
i) Modifying the MyOval class. Apply Steps c–f to the MyOval class. The line numbers
for MyOval will be the same as MyRectangle. Use the fillOval and drawOval meth-
ods in place of the fillRect and drawRect methods respectively.
j) Saving the application. Save your modified source code file.
k) Opening the template file. Open the DrawJPanel.java file in your text editor.
l) Modifying the shape constructor calls. You will now add a boolean argument to the
statements that invoke the shape constructors. On line 117, add an additional argu-
ment to the end of the list of arguments. The statement being modified is creating an
outlined oval, which means it should not be filled. So, the additional argument should
be the keyword false. This will result in instance variable filled, of the MyOval
class, being set to false. On line 123, add the additional argument, true, to the end
of the list of arguments. Now, when this line of code is executed, a MyOval object with
instance variable filled set to true will be created. On line 130, add the additional
argument, false, to the end of the list of arguments. When this line of code is exe-
cuted, a MyRectangle object with instance variable filled set to false will be cre-
ated. Finally, on line 136, add the additional argument, true, to the end of the list of
arguments. When this line of code is executed, a MyRectangle object with instance
variable filled set to true will be created.
m)Saving the application. Save your modified source code file.
n) Opening the Command Prompt window and changing directories. Open the Com-
mand Prompt window by selecting Start > Programs > Accessories > Command
Prompt. Change to your working directory by typing cd C:\SimplyJava\Advanced-
ScreenSaver.
o) Compiling the application. Compile your application by typing javac Screen-
Saver.java DrawJPanel.java MyRectangle.java MyOval.java.
p) Running the completed application. When your application compiles correctly, run
it by typing java ScreenSaver. Test your application by ensuring that shapes appear
and that the screen clears itself every thirty seconds.
q) Closing the application. Close your running application by clicking its close button.
r) Closing the Command Prompt window. Close the Command Prompt window by
clicking its close button.
814 Introduction to Polymorphism; an Expanded Discussion of Graphics Tutorial 27
27.12 (Logo Designer Application) Write an application that allows users to design a com-
pany logo. It should be able to draw lines as well as both filled and empty rectangles and
ovals with a simple coordinate input interface. Your GUI should look like Fig. 27.36.
a) Copying the template to your working directory. Copy the directory C:\Examples\
Tutorial27\Exercises\LogoDesigner to your C:\SimplyJava directory.
b) Opening the template file. Open the MyRectangle.java and MyOval.java files in
your text editor.
c) Modifying the MyRectangle and MyOval classes. Apply Steps c–j of the previous
exercise (Exercise 27.11) to your MyRectangle and MyOval classes. This will add the
ability to draw both filled and outlined shapes to your shape hierarchy.
d) Opening the template file. Open the DrawJPanel.java file in your text editor.
e) Adding the addShape method. At line 31, add a comment indicating that the method
will add the shape to shapeArray and then repaint. On line 32, add the method
header for the addShape method. This method does not return a value and takes an
argument of type MyShape named shape. Add shape to shapeArrayList by calling
the add method on shapeArrayList and passing it shape. Then, call the repaint
method so that the newly added shape will be displayed. Be sure to end the method
with a right brace on line 37.
f) Saving the application. Save your modified source code file.
g) Opening the template file. Open the LogoDesigner.java file in your text editor.
h) Invoking method addShape to draw a line. You will now invoke method addShape
in order to display a new line on the JPanel. At lines 279–280, call method addShape
on variable drawingJPanel. Pass it a new MyLine object created with the arguments
x, y, width, height and drawColor.
i) Invoking method addShape to draw an oval. You will now invoke method addShape
in order to display a new, outlined oval on the JPanel. On lines 284–285, call method
addShape on variable drawingJPanel. Pass it a new MyOval object created with the
arguments x, y, x + width, y + height, drawColor and false. On lines 289–290, call
addShape again, but this time draw a filled oval instead of an outlined one by chang-
ing the boolean value at the end of the argument list to true.
j) Invoking method addShape to draw a rectangle. You will now invoke method
addShape in order to display a new, outlined rectangle on the JPanel. On lines 294–
295, call method addShape on variable drawingJPanel. Pass it a new MyRectangle
object created with the arguments x, y, x + width, y + height, drawColor and false.
On lines 299–300, call addShape again, but this time draw a filled rectangle instead of
an outlined one by changing the boolean value at the end of the argument list to true.
Tutorial 27 Drawing Shapes Application 815
The mole
1. Be careful before you download any Whack A Mole games from the Internet. For a while
there was a virus-infected version that would read your hard drive while you were playing.
816 Introduction to Polymorphism; an Expanded Discussion of Graphics Tutorial 27
Color method. On line 35, add a comment indicating that the mole’s eyes will be
drawn, then, on line 36, call the fillOval method on g. Pass the following arguments
to method fillOval: x + 47, y + 84, 8 and 8. On line 37, call the fillOval method on
g. Pass the following arguments to method fillOval: x + 65, y + 84, 8 and 8.
f) Drawing the mole’s nose in the drawMole method. At line 39, call the setColor
method on g. Pass constant Color.BLACK to the setColor method. On line 40, call
the fillOval method on g. Pass the following arguments to method fillOval: x +
58, y + 97, 5 and 5.
g) Saving the application. Save your modified source code file.
h) Opening the Command Prompt window and changing directories. Open the Com-
mand Prompt by selecting Start > Programs > Accessories > Command Prompt.
Change to your working directory by typing cd C:\SimplyJava\WhackAMole.
i) Compiling the application. Compile your application by typing javac WhackA-
Mole.java Mole.java.
j) Running the completed application. When your application compiles correctly, run
it by typing java WhackAMole. Test your application by playing the game a few times.
Make sure that the mole looks as shown in Fig. 27.37.
k) Closing the application. Close your running application by clicking its close button.
l) Closing the Command Prompt window. Close the Command Prompt window by
clicking its close button.
▲
What does this code do? 27.14 What is the result of the following code? Assume that the classes used are those from
the Drawing Shapes application and that this method is in the PainterJPanel class.
What’s wrong with this code? 27.15 Find the error(s) in the following code. This is the definition for an actionPerformed
event handler for a JButton. This event handler should draw a rectangle on a JPanel.
Assume that the classes used are those from the Drawing Shapes application.
▲
Programming Challenge 27.16 (Moving Shapes Application) Enhance the Drawing Shapes application that you
created in this tutorial. Improve the application so that once you finish drawing a shape, the
shape will be given a random velocity and begin to move, bouncing off the walls of the
PaintJPanel. Your output should be capable of looking look like Fig. 27.38.
a) Copying the template to your working directory. Copy the directory C:\Examples\
Tutorial27\Exercises\MovingShapes to your C:\SimplyJava directory.
b) Opening the template file. Open the MyMovingShape.java file in your text editor.
c) Adding a method to your MyMovingShape class to change the position of the shape.
The abstract superclass for this inheritance hierarchy has been renamed MyMoving-
Shape. Add a public method named moveShape to the class. It should take no argu-
ments and have no return type. Two new instance variables, dx and dy, have been
added to the MyMovingShape class for you. Variable dx holds the distance along the
x-axis that the shape must travel in one move. Variable dy holds the distance along
the y-axis that the shape must travel in one move. Add dx to the x1 and x2 values and
add dy to the y1 and y2 values. Follow good programming practice by using the cor-
responding get and set methods instead of modifying the variables directly.
d) Finishing the moveShape method. Add two if statements to the moveShape method
to reverse the direction of the shape if it has hit a wall. The first if statement should
check if either x-coordinate (x1 or x2) is less than 0 or greater than 400. If this is
true then set the value of dx equal to the negative of itself. Make sure that you use
the correct get or set methods to do this. The second if statement should check if
either y-coordinate (y1 or y2) is less than 0 or greater than 340. If this is true then set
the value of dy equal to the negative of itself. Again, make sure that you use the cor-
rect get or set methods to do this.
e) Saving the application. Save your modified source code file.
f) Opening the template file. Open the PaintJPanel.java file in your text editor.
g) Modifying the moveTimerActionPerformed method. The moveTimerAction-
Performed method will iterate through every shape in shapeArrayList to call the
moveShape method of each shape. To do this, first declare a local variable of type
MyMovingShape named nextShape. Declare another local variable of type Iterator
named, shapesIterator and initialize it to the value returned by calling the itera-
tor method on shapeArrayList. Then, create a while loop whose condition is the
boolean returned by calling the hasNext method of shapesIterator. Within the
while loop, set nextShape equal to the reference returned by the next method of
shapesIterator. The next method will return the next indexed object in shapeAr-
rayList, which may be of type MyLine, MyRectangle, or MyOval. This means that
you will have to cast the returned object to a MyMovingShape object before storing it
818 Introduction to Polymorphism; an Expanded Discussion of Graphics Tutorial 27
in a variable of type MyMovingShape. Before ending the while loop, call the move-
Shape method on nextShape. The while loop you have created will now iterate
through every shape in shapeArrayList to call the moveShape method of each
shape.
h) Saving the application. Save your modified source code file.
i) Opening the Command Prompt window and changing directories. Open the Com-
mand Prompt by selecting Start > Programs > Accessories > Command Prompt.
Change to your working directory by typing cd C:\SimplyJava\MovingShapes.
j) Compiling the application. Compile your application by typing javac Moving-
Shapes.java PaintJPanel.java MyMovingShape.java.
k) Running the completed application. When your application compiles correctly, run
it by typing java MovingShapes. Test your application by drawing each of the three
shapes and pick a different color for each of them. Make sure that the shapes move
around and bounce off all of the walls.
l) Closing the application. Close your running application by clicking its close button.
m) Closing the Command Prompt window. Close the Command Prompt window by
clicking its close button.