CPSC 124, Spring 2006
Lab 9: Mosaic, Mousing, and Menus

For this lab, you will start work on a "MosaicDraw" program that allows the user to create pictures consisting of small colored rectangles. The pictures are meant to look something like mosaics made from small pieces of colored stone. For the second programming assignment, you will continue work on this program. Here is my version of the program that you will have after completing the lab:

Drag the mouse on the large drawing area to create a picture, and try the menu commands in the menu bar at the top of the applet. Note that there is some random variation in the color that is applied to the squares as you drag the mouse. This is supposed to make the mosaic look more like it is made of natural stone. You can also see the completed program by running MosaicDrawLab9Complete.jar, which also allows you to save pictures created in the program as files. (The commands for saving pictures are not included in the applet because applets are not allowed to access the file system for security reasons.)

To begin the lab, create a new Eclipse project and import all the files from /classes/s06/cs124/lab9, including: Controller.java, Menus.java, MosaicPanel.java, MosaicDrawApplet.java, and MosaicDrawFrame.java. For this project, you will be working on Controller.java and Menus.java. The main program, which you can run during development, is in MosaicDrawFrame.java. The MosaicPanel class defines the actual drawing area of the program, and is the same class that was used in the Tron lab. You will not make any modifications to MosaicPanel.java, but you will have to look through it to find some methods that you will need. MosaicDrawApplet.java will be used if you want to post your work as an applet on your web site.

A lot of work has already been done on the program. You should run MosaicDrawFrame to see what's there. All the commands work, except for "Fill" and "Clear" in the "Control" menu. Drawing is implemented, including the random color variation. If you select the "Erase" command from the "Tools" menu, you can erase the color from squares that have been drawn. If you select an unimplemented command, you will get a message that it has not been implemented.

This lab is due, as usual, next Tuesday.

Menus and Menu Bars

The first step in the lab is to add a "GridSize" menu to the menu bar and to add several new commands to the menus. The menu bar is defined by the Menus class. This class includes a method called createMenus() where the menus are constructed. The menu bar itself is an object belonging to the class JMenuBar, while the menus are objects belonging to the class JMenu. You should be able to learn everything that you need to know about creating menus for this lab by reading the createMenus() method. You should:

A grid size of "20x20" refers to a grid with 20 rows and 20 columns. You don't necessarily have to use exactly the same set of grid sizes that I used in my program, and you are welcome to use better names for the commands if you want.

Once you've added the necessary statements to createMenus(), run the program again to make sure that the menu and commands have been added correctly. If you select one of the new commands, you will get a message about an unimplemented command.

You will not have to do any further work on Menus.java. For the rest of the lab, you will be editing Controller.java.

Drawing a Rect

It will be useful to have a method for filling an entire rectangle of mosaic squares with color. You can use this to implement the "Fill" command and the "Draw 3x3" command. So, define a method fillRect(row1,col1,row2,col2) in the Controller class that fills in the rectangle that has corners at positions (row1,col1) and (row2,col2). You will need to use two nested for loops to do this. Don't forget to add a comment for the method!

It will be useful to have a method that will work even if row2 < row1 and/or col2 < col1, but if you just write for loops in the obvious way, they won't work correctly in such cases. The easy way to fix this is to define new variables in the method that have the correct ordering relationship. For example, you can set startRow = Math.min(row1,row2) and endRow = Math.max(row1,row2), and use the new variables in the for loop.

When writing your method, you should call the applyColor method to color each individual square. This method adds in the random variation to the color.

Implementing Commands

When the user selects a command from one of the menus, an ActionEvent is generated. The Menus class is set up to respond to these events by calling the doMenuCommand() method in the Controller class. To implement new commands, you have to add some code to this method. Once you've read this method to see how it works, implement the "Fill" command by calling

     fillRect( 0, 0, mosaic.getRowCount() - 1, mosaic.getColumnCount() - 1 );

You should also be able to implement the "Clear" command and all the commands in the "GridSize" menu. You don't need new methods to define these commands. Each of these commands can be implemented by calling a single method that is already defined in the mosaic object. This object belongs to the class MosaicPanel; look through MosaicPanel.java to see what methods it contains.

This leaves the "Draw 3x3" command still to be implemented. This command is a little different from the others because it doesn't perform an immediately visible action. Instead, it changes the state of the program. In this case, the state that is changed is the drawing tool that is currently being used. There are three drawing tools: "Draw", "Erase", and "Draw 3x3". When the user uses the mouse, what happens depends on which of these tools is currently selected. "Draw" and "Erase" are already implemented. You should look at the doMenuCommands() method to see what happens when the user selects these commands from the menu. The response to mouse events is contained in the methods mousePressed and mouseDragged. You should look at these methods to see how the current drawing tool affects what these methods do.

Implement the "Draw 3x3" command. When the "Draw 3x3" tool is selected, then the mouse should fill in a 3-by-3 block of squares instead of just painting a single square. You can fill in the block of squares by calling your fillRect method with appropriate parameters.

Moving On

There is nothing else to do for this lab, but if you have extra time, you might want to get started on the work for Programming Assignment 2. For one thing, you can add some more commands, such as "Erase 3x3" or "Draw 5x5". There are some additional "Color" commands that you can add, such as a command for changing the background color or the color of the grouting (the lines between the colored squares). It is also possible to turn off the grouting completely. The color commands can be implemented easily, since the MosaicPanel class already contains the methods that you will need.

One of the requirements for the project will be an "Undo" command that is capable of undoing the last action taken by the user. The MosaicPanel class has some support for this -- see the copyColorData and restoreColorData methods. However, "Undo" is still a little hard to get right, and if you are interested in getting started on it, you should ask me for some help.

David J. Eck, March 2006