We're now back with a regular lab, so you will need to come to lab with a design for all of the steps in the "How to Proceed" section. This week, you will be implementing a program we call "Scribbler." You have seen a simpler version of this program in class as a demo.
The image above will be a working version of the Scribbler if your web browser supports Java applets. You should experiment with this demonstration version after you finish reading the lab handout to make sure you understand exactly what we have in mind.
The Scribbler program has three modes: Draw mode, Move mode, and Color mode. The program starts in Draw mode. Draw mode, Move mode, and Color mode are selected by pressing buttons, and the color used by Color mode is selected by choosing a color from a choice component filled with color names. The modes behave as follows:
The program also has an "Erase Last" button that will erase the most recently drawn Scribble. Only the most recently drawn Scribble is erased. Pressing the button repeatedly will erase Scribbles in the reverse order of which they were drawn. Make sure your program does not crash after erasing the last one!
The starter for this lab is a working Scribbler, but it has only the Draw mode and a simplified Move mode that is capable of moving only the most recently drawn Scribble. You will need to add code that will manage your Scribbles to allow the various modes and the "Erase last" button to work correctly.
There are a number of step-by-step approaches you could take to solve this problem, but it is important that you have a plan, and that you add functionality one step at a time. Here is one possible ordering of the tasks. We recommend that you develop and test your program incrementally - make sure you have a working implementation at each step before moving on to the next.
Just as we do not know how many line segments will make up a Scribble when we start to draw one, we will not know how many Scribbles will be drawn and stored in our ScribbleCollection. In your Scribbler class you will need a variable with type ScribbleCollectionIfc that will be initialized with an object created from EmptyScribbleCollection. You will add new Scribbles to it using the constructor from ScribbleCollection as they are drawn. Consider carefully what methods your scribble collection needs to be able to support the functionality of the four modes. We have provided the skeleton of a ScribbleCollectionIfc interface, and ScribbleCollection and EmptyScribbleCollection classes.
We are providing some classes and interfaces to help you get started. These are almost identical to the Scribbler examples from lecture. Please download the starter to see the classes and interfaces we provide before working on your design. We also include the startup code for the Scribbler class and the ScribbleIfc interface.
The lab is due Monday at 11 PM. When your work is complete you should deposit in the appropriate dropoff folder a folder that contains your program and all of the usual files needed by JBuilder. Make sure the folder name includes your name and the phrase "Lab 8". Also make sure that your name is included in the comment at the top of each Java source file.
Before turning in your work, be sure to double check both its logical organization and your style of presentation. Make your code as clear as possible and include appropriate comments describing major sections of code and declarations.
Grading Point AllocationsValue | Feature |
Design preparation (3 points total) | |
1 points | Simplified color mode |
1 points | Erase mode |
1 point | ScribbleCollection class |
Code Quality (5 points total) | |
2 points | Descriptive comments |
1 point | Good names |
1 point | Good use of constants |
1 point | Appropriate formatting |
Design (6 points total) | |
1 point | Good use of boolean expressions, loops, conditionals |
1 point | Not doing more work than necessary |
2 points | Appropriate methods in ScribbleCollection |
2 points | Appropriate recursive structure in ScribbleCollection |
Correctness (6 points total) | |
1 point | Drawing the GUI components correctly |
1 point | Switching among modes correctly |
1 point | Draw mode adds correctly to the ScribbleCollection |
1 point | Move mode works correctly |
1 point | Color mode works correctly |
1 point | Erase button works correctly |
We are providing several classes and interfaces to help you get started. We include here printouts of the main program and the classes and interface for a single scribble. These are very similar to the Scribbler examples from lecture. Here is the code from the basic Scribbler class. You may need to add additional methods to it:
// A very simple drawing program. public class Scribbler extends WindowController implements ActionListener { // user modes // using ints rather than boolean to allow for extension to // other modes private static final int DRAWING = 1; private static final int MOVING = 2; private static final int COLORING = 3; // empty scribble as placeholder when nothing there. private static final EmptyScribble empty = new EmptyScribble(); // the current scribble private ScribbleIfc currentScribble; // the collection of scribbles private ScribbleCollectionIfc scribbles; // stores last point for drawing or dragging private Location lastPoint; // whether the most recent scribble has been selected for moving private boolean draggingScribble; // buttons that allow user to select modes private JButton setDraw, setMove, setErase, setColor; // Choice button to select color private JComboBox chooseColor; // new color for scribble private Color newColor; // label indicating current mode private JLabel modeLabel; // the current mode -- drawing mode by default private int chosenAction = DRAWING; // create and hook up the user interface components public void begin() { setDraw = new JButton("Draw"); setMove = new JButton("Move"); setColor = new JButton("Color"); setErase = new JButton("Erase last"); JPanel buttonPanel = new JPanel(); buttonPanel.add(setDraw); buttonPanel.add(setMove); buttonPanel.add(setColor); buttonPanel.add(setErase); chooseColor = new JComboBox(); chooseColor.addItem("red"); chooseColor.addItem("blue"); chooseColor.addItem("green"); chooseColor.addItem("yellow"); Panel choicePanel = new Panel(); choicePanel.add(chooseColor); Panel controlPanel = new Panel(new GridLayout(3,1)); modeLabel = new JLabel(" Current mode: drawing"); controlPanel.add(modeLabel); controlPanel.add(buttonPanel); controlPanel.add(choicePanel); add(controlPanel, BorderLayout.SOUTH); // add listeners setDraw.addActionListener(this); setMove.addActionListener(this); setErase.addActionListener(this); setColor.addActionListener(this); // make the current scribble empty currentScribble = empty; validate(); } // if in drawing mode then start with empty scribble // if in moving mode then prepare to move public void onMousePress(Location point) { if (chosenAction == DRAWING) { // start with an empty scribble for drawing currentScribble = empty; } else if (chosenAction == MOVING) { // check if user clicked on current scribble draggingScribble = currentScribble.contains(point); } // remember point of press for drawing or moving lastPoint = point; } // if in drawing mode, add a new segment to scribble // if in moving mode then move it public void onMouseDrag(Location point) { if (chosenAction == DRAWING) { // add new line segment to current scribble Line newSegment = new Line(lastPoint, point, canvas); currentScribble = new Scribble(newSegment, currentScribble); } else if (chosenAction == MOVING) { // if dragging, move current scribble if (draggingScribble) { currentScribble.move(point.getX() - lastPoint.getX(), point.getY() - lastPoint.getY()); } } // update for next move or draw lastPoint = point; } public void onMouseRelease(Location point) { // Add code when have collection of scribbles } // Set mode according to button pressed. public void actionPerformed(ActionEvent e) { if (e.getSource() == setDraw) { chosenAction = DRAWING; modeLabel.setText(" Current mode: drawing"); } else if (e.getSource() == setMove) { chosenAction = MOVING; modeLabel.setText(" Current mode: moving"); } } }
Here is the starting code for ScribbleIfc:
public interface ScribbleIfc { // returns whether point is contained in scribble boolean contains(Location point); // move scribble by dx in x-direction and dy in y-direction void move(double dx, double dy); }
Here is the starting code for Scribble:
// A class to represent a non-empty scribble public class Scribble implements ScribbleIfc { private Line first; // an edge line of the scribble private ScribbleIfc rest; // the rest of the scribble public Scribble(Line segment, ScribbleIfc theRest) { first = segment; rest = theRest; } // returns true iff the scribble contains the point public boolean contains(Location point) { return (first.contains(point) || rest.contains(point)); } // the scribble is moved xOffset in the x direction // and yOffset in the y direction public void move(double xOffset, double yOffset) { first.move(xOffset, yOffset); rest.move(xOffset, yOffset); } }
Here is the starting code for EmptyScribble:
/* Class representing an empty scribble */ public class EmptyScribble implements ScribbleIfc{ public EmptyScribble() { } // point is never in an empty scribble! public boolean contains(Location point) { return false; } // nothing to move, so do nothing! public void move(double dx, double dy) { } }
The start up code for the collection interface and classes is omitted here.
Computer Science
051
Department of Computer Science
Pomona College