In this lab you are going to
- Write a void method to draw a face
- Write a boolean method to tell if a string contains any capital letters
- Work with assert statements (for automated testing)
- Program a method to meet a known test
- Create an election ballot program from scratch.
void vs non-void Methods
In Alice you met methods and functions. Alice methods correspond to void methods in Java. They are "for effect" only: they cause something to happen (in Alice, some movement perhaps; in Java, the printing of a message perhaps) and do not return any value for the caller to use. Alice functions correspond to non-void methods in Java. Their primary purpose is to compute some value that will be returned to be used by the caller. non-void methods in Java need a return statement.
Study the program in Cross.java. You will notice:
- There is only one static method. main must be static because no objects exist at the time your program starts (when the operating system invokes the main method). But main creates a Cross object by calling the constructor.
- The constructor public Cross(int size) is a very special method. It is not void. Neither does it specify a return type. It has the same name (Cross) as the class itself. These are the characteristics of constructors. When called they create an object.
- There is a public void makeCross(int size) method. It has the effect of drawing a cross. But it does not, need not, cannot return a value. That's what void means!
- The method makeCross is called from the action listener for the JButton.
Be sure to create a project workspace for lab9.
Exercise 1
Adapt the cross-drawing program above so that it draws a face. The user should be presented with a JFrame like this:
![]()
and on providing a value and clicking the button should see a better face than:
![]()
Hint: Look at the documentation for the Graphics class. Look for a method that can draw a circle (remember that a circle is a special case of an ellipse). The arguments you supply are the coordinates of the TOP LEFT corner of the oval's bounding rectangle, and the width and height of the oval (the width and height will be equal for a circle, of course).
Name your class Ex1. This will require you to change all occurrences of Cross to Ex1 and to save the file as Ex1. Ask your lab instructor if you are not sure how to do this.
Make sure that you write your own comments so that we know if you understand the code.
Exercise 2
Non-void methods (also known as functions in Alice and by some programmers).
For the next exercise I want you to write a method that returns a boolean value to be displayed by the caller. Your method will be called by Ex2.java to confront the user with a JFrame that looks like this:
![]()
If I type Prof. Price Jones' name in the data box and click the button, the output is produced:
![]()
Had I typed the name with no upper case letters, the output field would read "Has Capitals: false".
Write a public boolean method named checkForCapitals that takes a String argument and returns true if the String has at least one upper case letter and false otherwise. Write your method and incorporate it into Ex2.java. You will need to write about three lines of code. Do not change any of the existing code. The resulting file should compile and run as advertised. Hint: Look at the documentation for the String class and use two of the methods given there and a logical operator to solve this problem neatly.
Testing
From the textbook we have two classes Box.java and BoxTester.java as discussed. Box.java is intended to contain methods pertaining to rectangular box shaped objects (As a matter of fact, volume() is the only method given here, but you can create more yourself. In fact, you will be asked to in the next chapter. BoxTester.java contains code to test the Box methods. The relevant lines are:
Box aBox = new Box(2.0, 3.0, 4.0); // test 1 double vol = aBox.volume(); assert vol == 24.0; System.out.print(" 1 "); aBox = new Box(6.0, 5.0, 4.0); // test 2 vol = aBox.volume(); assert vol == 120.0; System.out.print(" 2 "); System.out.println(" Passed!");The value of vol is set to Box.volume(2.0, 3.0, 4.0) and the assertion is made that vol == 24.0. If the assertion is true the program will continue and print a number 1.
Then vol is set to Box.volume(6.0, 5.0, 4.0). The program designer knows that this should evaluate to 120.0 and, for the purposes of testing, inserts the assertion assert vol == 120.0. Again, if the assertion is true, execution will continue, 2 will be printed, and then the final "passed!" is printed.
If any assertion fails, execution will terminate at that point and a rather rude message will be printed.
Go ahead and try it out now. Make sure Box.java and BoxTester.java are in your project and compiled. (Save them if necessary.) To run BoxTester.java you need the -ea flag that tells the Java system to enable assert tests. If you are unsure how to do this, ask your lab instructor.
You should see
indicating that the Box method has passed your tests.
1 2 Passed!Let's see if the Box methods work in the metric system. Assuming units are currently in inches let's convert the 6.0, 5.0 and 4.0 to centimetres. To do that we'll multiply each by 2.54. So
will set vol to the volume in cubic centimetres of the box.
aBox = new Box(6.0*2.54, 5.0*2.54, 4.0*2.54); vol = aBox.volume()We know from test 2 that the volume of this box in cubic inches is 120.0.
There are cubic centimetres in a cubic inch. So the volume in cubic centimetres should be 120.0 * Math.pow(2.54, 3).
We can test this by adding the assertion
assert vol == 120.0*Math.pow(2.54, 3);Accordingly, modify BoxTester by adding these lines after System.out.print(" 2 "); and before System.out.println(" Passed! ");
Save again to compile, and run the program. Note in your lab notebook what happens.
aBox = new Box(6.0*2.54, 5.0*2.54, 4.0*2.54); // test 3, vol = aBox.volume(); // convert inches to centimetres. assert vol == 120.0*Math.pow(2.54, 3); System.out.print(" 3 ");The problem is that floating point roundoff errors have occurred. Since calculation in the computer is all performed in binary it is very hard to predict just how much error will happen. In fact, it is not the case that roundoff will occur the same on different machines!
The moral of this tale is:
Never, ever, ever use == to compare doubles
Maybe we should replace the line
by, say
assert vol == 120.0*Math.pow(2.54, 3);This asserts that the difference between vol and is less than .
assert (vol - 120.0*Math.pow(2.54, 3)) < 3.0e-10;
Exercise 3
Change the assertion
so that instead you assert that the absolute value of the difference between vol and 120.0*Math.pow(2.54, 3) is less than . There is an absolute value method in the Math class that you should use. When you have successfully completed this step you should find that the output from BoxTester is
assert vol == 120.0*Math.pow(2.54, 3);At that point, you may want to go back to the previous two assert statements and amend them to take account of possible roundoff error. Save your finished testing program as BoxTester.java.
1 2 3 Passed!
Exercise 4
Programming to test specifications: For your last exercise I'm going to ask you to write a method for the box class to compute the surface area of the box. You should recall from your happy kindergarten days that the formula for this is
You will need to modify the (incorrect) surfaceArea() return value from Box.java. Before you proceed, take a look at BoxAreaTester.java. If the output of this program is
then your method meets my test.
Testing Box.surfaceArea(): 1 2 3 Passed!Write a correct public double surfaceArea() method for the Box class. Test it with my program.
Simple election
In the next couple of exercises, we are going to develop a voting machine, i.e. an computer application that would record votes for each candidate. Feel free to change the names of the candidates to suit your entertainment.
You will start of with a simple program that does everything. Then you will try to organize your program and abstract away the candidates, i.e. you would make a separate class to represent candidates in order to make your program more flexible and easier to accomodate a larger number of candidates. You will then to modify and enhance your election and candidate classes. At the end, I will ask you to reflect on our own turtle worlds that we had started to program from scratch.
Our first ballot paper will be a simple JFrame that works like this:
I will lead you through the steps you need to take to make this one.
As usual, pick your workspace and make a project for this lab. Also let's keep all this lab's code in a package so we don't get the warning about not using the default package. If you need help on any of this, ask a lab instructor right away!
Now make a new class. Name it Election1 and have it extend javax.swing.JFrame and implement the interface java.awt.event.MouseListener. Be sure also to ask for Eclipse to create your main method. Again, if in any doubt, consult with a lab instructor.
At this point Eclipse will have generated a file with all the methods needed for a MouseListener. They will all have empty bodies. The only one we need to worry about is mouseClicked. Assuming you are keeping track of the votes for each candidate in its own variable (mine are called joeVotes and sarahVotes, it is very easy to write this event handler. Since this is a demo, I'll even give you my code!
public void mouseClicked(MouseEvent clickEvent) { if (clickEvent.getX() < getWidth()/2) { joeVotes++; repaint(); } else { sarahVotes++; repaint(); } }Of course, we'll need a paint method, so that the repaint makes sense. How about
public void paint(Graphics g) { g.setColor(Color.white); g.fillRect(0,0,getWidth(),getHeight()); g.setColor(Color.black); g.drawString("Click on the left half to vote", MARGIN, 2*MARGIN); g.drawString("for Joe \"The Plumber\" Palin", MARGIN, 3*MARGIN); g.drawString("Click on the right half to vote", getWidth()/2 + MARGIN, 2*MARGIN); g.drawString("for Kay Sarah Sera", getWidth()/2 + MARGIN, 3*MARGIN); g.drawString("Joe has "+ joeVotes, MARGIN, 6*MARGIN); g.drawString("Kay has "+ sarahVotes, getWidth()/2 + MARGIN, 6*MARGIN); g.drawLine(getWidth()/2, 0, getWidth()/2, getHeight()); }In case you're wondering, MARGIN is an int constant. You can let Eclipse write the code to declare it if you like. In that case, Eclipse will add the declaration:
private static final int MARGIN = 0;The purpose of the margin is to keep the text away from the edges of the JFrame and to separate the lines of output. 0 is an entirely inappropriate value. Set it to 20 or so.
Right below the constant declaration is where you will put your declarations for the int variables to keep track of each candidate's votes. In my case I wrote:
private int joeVotes, sarahVotes;Next we need a constructor where we set all our initializations etc. Here is mine:
public Election1() { setTitle("Electronic Ballot Paper"); setSize(600,200); setVisible(true); addMouseListener(this); setDefaultCloseOperation(EXIT_ON_CLOSE); joeVotes = sarahVotes = 0; repaint(); }Be sure you understand what each line does. If in any doubt, consult with a lab instructor. You should be able to guess what
does, but again feel free to ask your lab instructor.
joeVotes = sarahVotes = 0;The final think you need to do is create the object and you do that in your main method. Here's mine:
public static void main(String[] args) { new Election1(); }Seriously now, you have all the code you need.
Exercise 5
Follow the steps given above to create Election1. Compile it and run it. If you have any problem whatsoever, ask your lab instructor.
Candidates as Objects
You probably noticed that there is very little difference between the candidates. At least from the point of view of the electronic ballot designer. They have:
- different names
- different vote-tallies
- different positions on the ballot paper
One of the most powerful techniques known to computer scientists is abstraction. You notice the similarities between two entities and make a single class to represent both entities. You notice the differences between the entities and make sure you have parameters for expressing the differences and instance variables for storing the differences.
For example. I would abstract the similarities and differences between our candidates from the last exercise thus:
import java.awt.Color; public class Candidate { private Color color; protected String name; protected int votes; private int x, y, width, height; public Candidate(Color c, String name, int x, int y, int width, int height) { votes = 0; this.name = name; color = c; this.x = x; this.y = y; this.width = width; this.height = height; } }(In addition to the qualities described earlier, I've also added a color attribute to the candidate. We'll use this shortly to color the ballot paper appropriately. The reason why the instance variable votes is protected rather than private has to do with inheritance, which we will see later in this lab.)
Notice how the position on the ballot paper is represented with the usual 4 ints that Java likes to use: x and y for the top left corner and then the width and the height.
Exercise 6
Make a class called Candidate in your Java project. Use the code given above. Now copy your code from Election1 into a new class Election2. You will need to
- change the header to read public class Election2 extends JFrame implements MouseListener
- change the header of the constructor to read public Election2()
- change the body of the main method to create an instance of Election2 not Election1.
Your code for Election2 at this stage should work exactly like Election1. if it doesn't, consult with a lab instructor right away.
Now let's break it.
Replace the declaration private int joeVotes, sarahVotes; by private Candidate joe, sarah;
Replace the line joeVotes = sarahVotes = 0; by
joe = new Candidate(Color.red, "Joe \"the plumber\" Palin", MARGIN, MARGIN, getWidth()/2 - MARGIN, getHeight()-MARGIN); sarah = new Candidate(Color.green, "Kay Sarah Sera", MARGIN+getWidth()/2, MARGIN, getWidth()/2 - MARGIN, getHeight()-MARGIN);Replace the old paint method by
public void paint(Graphics g) { super.paint(g); if (joe != null && sarah != null) { joe.paint(g); sarah.paint(g); } }and replace the old mouseClicked method by
public void mouseClicked(MouseEvent clickEvent) { if (clickEvent.getX() < getWidth()/2) { joe.registerVote(); repaint(); } else { sarah.registerVote(); repaint(); } }If you were to omit the != null check and simply write
your program would work just fine, but you would get an error message the first time the program tried to pain the frame. Do you see why?
public void paint(Graphics g) { joe.paint(g); sarah.paint(g); }At this point, Eclipse should be telling you about four errors. The lines asking joe and sarah to paint(g) and to registerVote() are all tagged.
We are re-arranging our program so that each candidate is responsible for keeping track of her or his own vote tally, and is responsible for drawing its own information on our JFrame.
Exercise 7
Add the two methods to the Candidate class so that program Election2 works just like Election1 except that each candidate's information is printed on the appropriately colored background.
One candidate, one listener
In the last section, we made each candidate responsible for printing its information, coloring its share of the ballotpaper, and maintaining its own vote count. Now let's make it responsible for its own clicks.
It is difficult to attach a listener to a portion of the JFrame unless that portion is actually a Component. Our Candidate2 class will:
- extend JButton
- implement MouseListener.
- not need to keep track of its own position and size!
This is actually very cool: In the previous program you needed an if statement to decide which half of the frame the user clicked on. Now, you can do without an if. Whichever candidate the user clicks on, that is the object that detects the click and processes it. There is no need to verify which candidate. Your program should be entirely if-free.
So, in your project create a class Candidate2 to extend JButton and implement MouseListener. Eclipse will give you all the headers. You need to work on a constructor and on the mouseClicked method.
You will need
- instance variables for name color votes
- In the constructor you will need
- parameters Color c and String name
- a call to super()
- initialize votes
- initialize color
- setForeground(color)
- setText(name+" has "+votes+" votes")
- addMouseListener(this)
- Your registerVote() mehtod will need to
- increment votes
- update the information with setText(name+" has "+votes+" votes")
- Your mouseCliked method will simply call registerVote
That's all. Make sure Candidate2 compiles.
Exercise 8
Make a new class Election3 with the following code
import java.awt.Color; import java.awt.Container; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.GridLayout; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JFrame; /** * @author rhyspj * */ public class Election3 extends JFrame { Candidate2 biden, palin; public Election3() { setTitle("Electronic Ballot Paper"); setSize(600,200); setVisible(true); biden = new Candidate2(Color.red, "Joe \"the plumber\" Palin"); palin = new Candidate2(Color.green, "Kay Sarah Sera"); Container me = getContentPane(); setDefaultCloseOperation(EXIT_ON_CLOSE); me.setLayout(new GridLayout(0,2)); me.add(biden); me.add(palin); validate(); } /** * @param args */ public static void main(String[] args) { new Election3(); } }Study this code, consult the API docuementation and ask your lab instructor questions if you need to. For example what's with the setLaylut messages? What is a FlowLayout?
Work on your Candidate2 class until the combination works like the applet below.
Inheritance
Your electronic ballot paper so far just keeps track of the candidates and the votes for each. We want to make it a bit smarter. We want to add a button that tallies the results so far and predicts a winner.
The action listener for that button will need to ask each candidate how many votes they currently have, figure out who is leading, and display the information.
So each candidate will need a public int getVotes() method to return the number of votes it currently has.
Rather than create a Candidate3 class from scratch, we will write
A Candidate3 object thus can be constructed just like a Candidate2 object, has all the functionality of a Candidate2 object plus it has a getVotes() method that returns the current vote count for that candidate. Incidentally, because it needs access to votes which is declared in the parent class Candidate2, it is important that Candidate2 declared votes to be protected rather than private.
import java.awt.Color; public class Candidate3 extends Candidate2 { public Candidate3(Color c, String name) { super(c, name); } public int getVotes() { return votes; } }For our next exercise, we are going to place all our candidates in a Vector<Candidate3>. This is rather like a List in Alice. You can add items to a Vector and you can perform actions on each member of a Vector.
For example, here is a program to add together the votes of three candidates:
The program is a JApplet rather than a JFrame as you will program. It produces the behavior below:
Things to note in my program:
- It is a JApplet. You will need a JFrame.
- I declare a private Vector<Candidate3>stooges;
- I instantiate stooges = new Vector<Candidate3>();
- I add the three stooges to the Vector
- I can loop through every member of the stooges (and do so twice) by using a for loop (called an enhanced for loop for historical reasons) like this: for (Candidate3 person : stooges)
- The general form of the enhanced for loop is: for (Type identifier : structure) statement: Multiple statements require the use of curly brackets.
- I am using an anonymous inner class to provide an ActionListener for the tote JButton.
Exercise 9
Modify Candidate3 so that you also have a getName() method. Then create a JFrame that behaves something like this:
Own your own
Enhance your electronic ballot paper in some imaginative way. Here's my sorry attempt: (Be sure to keep a close eye on that pesky wabbit, though!)
Exercise 10
I'm sure you can do better. Make a fun electronic election ballot paper
How to submit your homework
Create a folder on your computer and name it 'CS053-Spring10' (if you do not have it already). Create another folder and name it 'lab9'. In the newly created 'lab9' folder copy your solutions to the exercises: Exercise1.java, Exercise2.java, Exercise3.java, and so on...
Next, go back up to your folder 'CS053-Spring10', right click on your folder 'lab9' and compress it either in a or file.
Your newly compressed file should be named:
- FirstName_LastName_Lab_9.zip or
- FirstName_LastName_Lab_9.rar
After you have compressed your homework, then proceed to submit it via Blackboard.
Got problems? If you have any problems make sure you clear them with your lab instructor because if you do not follow these requirements for submission your lab homework submissions will not be accepted and you will get zero points.