This lab consists of two exercises in which you will use objects. In the first exercise, you will create objects belonging to one of Java's standard classes, and you will call some methods in those objects. In the second exercise, you will be working with events in a simple GUI application.
To begin the lab, you should create a directory or Eclipse project named lab8 and copy the files named FirstEvents.java, MosaicPanel.java, and ThreeN.java from /classes/f09/cs124 into your lab8 folder. You will need ThreeN.java for the first exercise and FirstEvents.java for the second exercise. You will also need a copy of TextIO.java for the first exercise.
This lab is due next Thursday, October 29, as usual. In addition, the second longer project from Lab 6 is due next Tuesday, October 27.
The "3N+1" sequence was used as an example several times in the textbook. The file ThreeN.java is a simple implementation. You can run the program to see what it does, and you can review the definition of the 3N+1 sequence in Section 3.2.2.
One problem with this program is that the number N can get so large that it can no longer be represented as a 32-bit integer. When this happens, you get no warning, but the program is no longer computing the sequence correctly. This is a general problem when working with 32-bit integers. In mathematics, integers can be arbitrarily big. Why can't the computer use arbitrarily big integers?
In fact, it can (limited only by the amount of memory that is available). In Java, the standard class BigInteger represents integers that can be arbitrarily large. The first exercise of the lab is to modify the ThreeN program to use BigInteger instead of int, so that it will be able to work with integers of any size. The first step is to import the BigInteger class, which is found in the package java.math. Use this directive at the top of the source code:
BitIntegers are objects, not primitive values. That means that you have to create them with a constructor, using the new operator. The BigInteger constructor takes a parameter of type String. The string should contain the number written out in ordinary, decimal notation. For example, to create BigIntegers to represent the integers 1 and 123456789012345678901234567890, you could say:
BigInteger one, reallyBig; one = new BigInteger("1"); reallyBig = new BigInteger("123456789012345678901234567890");
Furthermore, when using BigInteger, you can't do arithmetic with the operators +, -, *, /, and %. Instead, you have to use instance methods. For example, to add 1 to reallyBig, you would say
reallyBig = reallyBig.add(one);
The methods subtract, multiply, divide, and mod work similarly (where mod is the equivalent of the % operator).
Again, since BigIntegers are objects, they should not be compared with the == operator. Instead, use the equals method, just as you do for strings.
The program FirstEvents.java is another application that uses a "mosaic" of small, colored squares, like the program from Lab 7. However, in this lab, instead of using static methods to control the mosaic, you will use instance methods in an object of type MosaicPanel. Furthermore, you be working with events and event objects.
Events can be generated by user actions, such as pressing or dragging the mouse, typing on the keyboard, or clicking a button. The system can be configured to call an event-handling method when an event occurs. Information about the event is passed to the method as a parameter, in an object that holds information about the event. For example, an event generated by the mouse is represented by an object of type MouseEvent. A MouseEvent object contains information such as the x- and y-coordinates of the mouse cursor. The event-handling method can use this information to decide how to respond to the event. Similarly, when the user clicks on a button, an event of type ActionEvent is generated.
An important thing to understand is that events can occur any time and in any order, at the whim of the user. This is asynchronous programming, and it is very different from a command-line program where you can write a step-by-step script in which you ask the user a question, wait for a response, ask another question, and so on.
You should run the FirstEvents program to see what it does. A simple user interface for the program has already been set up. (This is something that you will learn how to do for yourself later in the course.) That is, a window has been laid out with a MosaicPanel and some buttons, and the program has been configured to receive notification of mouse events from the panel. However, only one response has been programmed: If you click the "Random Fill" button, the mosaic will be filled with randomly colored squares. Your job is to program responses to other events. You will only need to add about two dozen lines of code to the program, but it should help you to understand how events and GUI programming work.
Step 1: The Clear Button. When the user clicks one of the buttons, the actionPerformed() method is called. This method has a parameter of type ActionEvent. If evt is that parameter, then the method evt.getActionCommand() returns a String that describes the event -- in this case, the text from the button. The actionPerformed method already responds correctly when the action command is "Random Fill". Extend it to respond correctly to the "Clear" action command. (Note that mosaic is an instance variable in FirstEvents, of type MosaicPanel. This object has a clear() method.)
Step 2: Mouse Events. When the user presses or drags the mouse, the color of the square that contains the mouse cursor should be changed. This allows the user to "draw" on the mosaic panel. The instance variable drawingColor, of type Color, tells what color the squares should be changed to. When the user presses the mouse on the mosaic panel, the mousePressed method is called. Fill in the contents of this method so that it will change the color of the square where the mouse was pressed. The parameter, evt, in this method has methods evt.getX() and evt.getY() that return the coordinates of the point where the mouse was pressed. You can use the setColor method of the mosaic object to change the color of the square -- but to use that, you need to know the row and column in the mosaic where the user pressed the mouse. That means that you have to translate the x and y coordinates into column and row numbers that you can use in the setColor method. Fortunately, this is easy, given that each square is 20 pixels on a side. After programming the mousePressed method -- and checking that it works -- you can copy the exact same commands into the mouseDragged method, which will allow the user to color squares by dragging the mouse over them.
Step 3: The Color Fill Button. The "Color Fill" button is supposed to let the user select a color and then use that color to fill the entire mosaic panel. To let the user select a color, you want to put up a "color chooser dialog box." Fortunately, Java has a static method in the JColorChooser class that makes this easy. That method is used like this:
Color newColor; // This will be the color selected by the user newColor = JColorChooser.showDialog(this, "Window Title", oldColor);
The first parameter, this, is called the "parent" of the dialog box -- you won't understand this for now; just use the actual word this. The second parameter is a string that will be used as the title of the color chooser window. The third parameter is meant to represent the current color, before the user makes a new selection; if you don't have a current color to pass it, use the value null. The return value, newColor, is the color selected by the user. However, if they user cancels the dialog without selecting a color, then the return value is null. You should use this method to implement the "Color Fill" command. If the user actually does select a color, you should fill the mosaic with the color. (Note that the mosaic object contains a fill() method that can be used to do this.)
Step 4: Changing the Drawing Color. The "Pick Draw Color" method is supposed to let the user select a new color to use for drawing. Use the JColorChooser class again to implement this command. Note that this command has no immediate effect on the mosaic. It simply changes the value of the drawingColor instance variable, so that the new color will be used for future drawing operations.