As promised, we are back with a whole new Paint Applet, this time using javax.swing and JFrame. If you havent seen our previous attempt at the Paint Brush Applet, you can view it here. The bugs that we encountered last time have been somewhat solved in this applet.
First of all, the output looks something like this:
BUGS AND HOW THEY ARE SOLVED:
Now we will show how the 3 bugs mentioned in Paint Brush Applet are solved.
First of all, the output looks something like this:
As you can see, one can draw rectangle, round rectangle and ovals to their file. The applet provides facility to save their file, rename it, save it in a different location and to view saved files.
You can view the actual source code here. We have tried our best to comment wherever necessary. Still, if you have any doubts or any kind of ambiguity, please feel free to leave a comment:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.*; | |
import java.awt.event.*; | |
import javax.swing.*; | |
import java.util.ArrayList; | |
import java.io.*; | |
@SuppressWarnings("serial") | |
public class Paint2 extends JFrame { | |
public static void main(String[] args) { | |
new Paint2(); | |
} | |
String fileName; | |
JCheckBoxMenuItem addLargeShapes; // Controls whether newly added | |
// shapes will be large or small. | |
JCheckBoxMenuItem addBorderedShapes; // Controls whether newly added | |
// will have a black border. | |
JRadioButtonMenuItem red, green, blue, // Control the color | |
cyan, magenta, yellow, // of newly added shapes. | |
black, gray, white; | |
JPopupMenu popup; // The pop-up menu, which is used for editing shapes. | |
public Paint2() { | |
super("Paint - Tejash Desai"); | |
/* Create the "canvas" which displays the shapes and serves as | |
the content pane of the frame. */ | |
ShapeCanvas canvas = new ShapeCanvas(); | |
setContentPane(canvas); | |
/* Create the menu bar and the menus */ | |
JMenuBar menubar = new JMenuBar(); | |
setJMenuBar(menubar); | |
JMenu fileMenu = new JMenu("File"); | |
fileMenu.setMnemonic('F'); | |
menubar.add(fileMenu); | |
JMenu addShapeMenu = new JMenu("Add Shapes"); | |
addShapeMenu.setMnemonic('A'); | |
menubar.add(addShapeMenu); | |
JMenu shapeColorMenu = new JMenu("Edit Color"); | |
shapeColorMenu.setMnemonic('E'); | |
menubar.add(shapeColorMenu); | |
JMenu optionsMenu = new JMenu("Options"); | |
optionsMenu.setMnemonic('O'); | |
menubar.add(optionsMenu); | |
//the file menu | |
JMenuItem newCmd = new JMenuItem("New"); | |
newCmd.setAccelerator( KeyStroke.getKeyStroke("ctrl N") ); | |
newCmd.addActionListener(canvas); | |
fileMenu.add(newCmd); | |
JMenuItem openCmd = new JMenuItem("Open..."); | |
openCmd.setAccelerator( KeyStroke.getKeyStroke("ctrl O") ); | |
openCmd.addActionListener(canvas); | |
fileMenu.add(openCmd); | |
JMenuItem saveCmd = new JMenuItem("Save..."); | |
saveCmd.setAccelerator( KeyStroke.getKeyStroke("ctrl S") ); | |
saveCmd.addActionListener(canvas); | |
fileMenu.add(saveCmd); | |
JMenuItem quitCmd = new JMenuItem("Quit"); | |
quitCmd.setAccelerator( KeyStroke.getKeyStroke("ctrl Q") ); | |
quitCmd.addActionListener(canvas); | |
fileMenu.add(quitCmd); | |
//the Add menu | |
JMenuItem rect = new JMenuItem("Rectangle"); | |
rect.setAccelerator( KeyStroke.getKeyStroke("ctrl R") ); | |
addShapeMenu.add(rect); | |
rect.addActionListener(canvas); | |
JMenuItem oval = new JMenuItem("Oval"); | |
oval.setAccelerator( KeyStroke.getKeyStroke("ctrl V") ); | |
addShapeMenu.add(oval); | |
oval.addActionListener(canvas); | |
JMenuItem roundrect = new JMenuItem("Round Rect"); | |
roundrect.setAccelerator( KeyStroke.getKeyStroke("ctrl D") ); | |
addShapeMenu.add(roundrect); | |
roundrect.addActionListener(canvas); | |
/* The color menu. A ButtonGroup is used | |
to make sure that only one color is selected. */ | |
ButtonGroup colorGroup = new ButtonGroup(); | |
red = new JRadioButtonMenuItem("Red"); | |
shapeColorMenu.add(red); | |
colorGroup.add(red); | |
red.setSelected(true); | |
green = new JRadioButtonMenuItem("Green"); | |
shapeColorMenu.add(green); | |
colorGroup.add(green); | |
blue = new JRadioButtonMenuItem("Blue"); | |
shapeColorMenu.add(blue); | |
colorGroup.add(blue); | |
cyan = new JRadioButtonMenuItem("Cyan"); | |
shapeColorMenu.add(cyan); | |
colorGroup.add(cyan); | |
magenta = new JRadioButtonMenuItem("Magenta"); | |
shapeColorMenu.add(magenta); | |
colorGroup.add(magenta); | |
yellow = new JRadioButtonMenuItem("Yellow"); | |
shapeColorMenu.add(yellow); | |
colorGroup.add(yellow); | |
black = new JRadioButtonMenuItem("Black"); | |
shapeColorMenu.add(black); | |
colorGroup.add(black); | |
gray = new JRadioButtonMenuItem("Gray"); | |
shapeColorMenu.add(gray); | |
colorGroup.add(gray); | |
white = new JRadioButtonMenuItem("White"); | |
shapeColorMenu.add(white); | |
colorGroup.add(white); | |
/* Create the "Clear" menu item, and add it to the | |
"Options" menu. The canvas will listen for events | |
from this menu item. */ | |
JMenuItem clear = new JMenuItem("Clear"); | |
clear.setAccelerator( KeyStroke.getKeyStroke("ctrl C") ); | |
clear.addActionListener(canvas); | |
optionsMenu.add(clear); | |
optionsMenu.addSeparator(); // Add a separating line to the menu. | |
addLargeShapes = new JCheckBoxMenuItem("Add Large Shapes"); | |
addLargeShapes.setSelected(true); | |
optionsMenu.add(addLargeShapes); | |
addBorderedShapes = new JCheckBoxMenuItem("Add Shapes with Border"); | |
addBorderedShapes.setSelected(true); | |
optionsMenu.add(addBorderedShapes); | |
optionsMenu.addSeparator(); | |
/* Create a menu for background colors.*/ | |
JMenu background = new JMenu("Background Color"); | |
optionsMenu.add(background); // in the above cases, we used to add JMenuItem to a JMenu | |
//here, we add a JMenu to another JMenu creating a heirarchial menu | |
background.add("Red").addActionListener(canvas); | |
background.add("Green").addActionListener(canvas); | |
background.add("Blue").addActionListener(canvas); | |
background.add("Cyan").addActionListener(canvas); | |
background.add("Magenta").addActionListener(canvas); | |
background.add("Yellow").addActionListener(canvas); | |
background.add("Black").addActionListener(canvas); | |
background.add("Gray").addActionListener(canvas); | |
background.add("White").addActionListener(canvas); | |
/* Create the pop-up menu and add commands for editing a | |
shape. This menu is not used until the user performs | |
the pop-up trigger mouse gesture on a shape. */ | |
popup = new JPopupMenu(); | |
popup.add("Delete Shape").addActionListener(canvas); | |
popup.addSeparator(); | |
popup.add("Bring to Front").addActionListener(canvas); | |
popup.addSeparator(); | |
popup.add("Make Large").addActionListener(canvas); | |
popup.add("Make Small").addActionListener(canvas); | |
popup.addSeparator(); | |
popup.add("Add Black Border").addActionListener(canvas); | |
popup.add("Remove Black Border").addActionListener(canvas); | |
popup.addSeparator(); | |
popup.add("Set Color to Red").addActionListener(canvas); | |
popup.add("Set Color to Green").addActionListener(canvas); | |
popup.add("Set Color to Blue").addActionListener(canvas); | |
popup.add("Set Color to Cyan").addActionListener(canvas); | |
popup.add("Set Color to Magenta").addActionListener(canvas); | |
popup.add("Set Color to Yellow").addActionListener(canvas); | |
popup.add("Set Color to Black").addActionListener(canvas); | |
popup.add("Set Color to Gray").addActionListener(canvas); | |
popup.add("Set Color to White").addActionListener(canvas); | |
setDefaultCloseOperation(EXIT_ON_CLOSE); | |
/* Set the size and location of the frame. */ | |
setLocation(20,50); | |
setSize(550,420); | |
setVisible(true); | |
} // end constructor | |
//---- Nested class definitions --- | |
// | |
// These are just like regular classes, except that they are defined inside | |
// another class (and hence have full names, when used outside this class, such | |
// as ShapeDraw.ShapeCanvas). | |
class ShapeCanvas extends JPanel | |
implements ActionListener, MouseListener, MouseMotionListener { | |
ArrayList shapes = new ArrayList(); | |
// holds a list of the shapes that are displayed on the canvas | |
ShapeCanvas() { | |
setBackground(Color.white); | |
addMouseListener(this);//for right-clicking components and choosing options like "Bring to front" | |
addMouseMotionListener(this);//to drag components in the screen | |
} | |
public void paintComponent(Graphics g) { | |
super.paintComponent(g); // First, fill with background color. | |
int top = shapes.size(); | |
for (int i = 0; i < top; i++) { | |
Shape s = (Shape)shapes.get(i); | |
s.draw(g); | |
} | |
} | |
public void actionPerformed(ActionEvent evt) { | |
// Called to respond to action events from the | |
// menus or pop-up menu. | |
String command = evt.getActionCommand(); | |
if (command.equals("New")) { | |
//the "new" command doesn't open a new file. It just clears the current file. | |
//it is somewhat similar to "clear" command | |
shapes.clear(); // Remove all items | |
setBackground(Color.white); // Clear to white. | |
} | |
else if (command.equals("Open...")) { | |
openFile();//call the custom open function | |
} | |
else if (command.equals("Save...")) { | |
saveFile();//call the custom save function | |
} | |
else if (command.equals("Quit")) { | |
System.exit(0);//system is exited either when Quit is pressed or when window is closed | |
} | |
else if (command.equals("Clear")) { | |
shapes.clear(); | |
//this is the difference b/w new and clear command. new doesn't call the paint() again. | |
repaint(); | |
} | |
else if (command.equals("Rectangle")) | |
addShape(new RectShape()); | |
else if (command.equals("Oval")) | |
addShape(new OvalShape()); | |
else if (command.equals("Round Rect")) | |
addShape(new RoundRectShape()); | |
else if (command.equals("Red")) | |
setBackground(Color.red); | |
else if (command.equals("Green")) | |
setBackground(Color.green); | |
else if (command.equals("Blue")) | |
setBackground(Color.blue); | |
else if (command.equals("Cyan")) | |
setBackground(Color.cyan); | |
else if (command.equals("Magenta")) | |
setBackground(Color.magenta); | |
else if (command.equals("Yellow")) | |
setBackground(Color.yellow); | |
else if (command.equals("Black")) | |
setBackground(Color.black); | |
else if (command.equals("Gray")) | |
setBackground(Color.gray); | |
else if (command.equals("White")) | |
setBackground(Color.white); | |
else if (clickedShape != null) { | |
// Process a command from the pop-up menu. | |
if (command.equals("Delete Shape")) | |
shapes.remove(clickedShape); | |
else if (command.equals("Bring to Front")) { | |
/*Suppose we have a rectangle over a circle. If we remove the circle and then | |
* add it again after the rectangle, it will produce the effect of "bringing to front" | |
*/ | |
shapes.remove(clickedShape);//removes the first occurrence of clickedShape | |
shapes.add(clickedShape); //adds clickedShape to the end of the ArrayList | |
} | |
else if (command.equals("Make Large")) | |
clickedShape.setSize(100,60); | |
else if (command.equals("Make Small")) | |
clickedShape.setSize(50,30); | |
else if (command.equals("Add Black Border")) | |
clickedShape.setDrawOutline(true); | |
else if (command.equals("Remove Black Border")) | |
clickedShape.setDrawOutline(false); | |
else if (command.equals("Set Color to Red")) | |
clickedShape.setColor(Color.red); | |
else if (command.equals("Set Color to Green")) | |
clickedShape.setColor(Color.green); | |
else if (command.equals("Set Color to Blue")) | |
clickedShape.setColor(Color.blue); | |
else if (command.equals("Set Color to Cyan")) | |
clickedShape.setColor(Color.cyan); | |
else if (command.equals("Set Color to Magenta")) | |
clickedShape.setColor(Color.magenta); | |
else if (command.equals("Set Color to Yellow")) | |
clickedShape.setColor(Color.yellow); | |
else if (command.equals("Set Color to Black")) | |
clickedShape.setColor(Color.black); | |
else if (command.equals("Set Color to Gray")) | |
clickedShape.setColor(Color.gray); | |
else if (command.equals("Set Color to White")) | |
clickedShape.setColor(Color.white); | |
repaint();//paint function will draw all the shapes in the ArrayList | |
} | |
} | |
void addShape(Shape shape) { | |
if (red.isSelected()) | |
shape.setColor(Color.red); | |
else if (blue.isSelected()) | |
shape.setColor(Color.blue); | |
else if (green.isSelected()) | |
shape.setColor(Color.green); | |
else if (cyan.isSelected()) | |
shape.setColor(Color.cyan); | |
else if (magenta.isSelected()) | |
shape.setColor(Color.magenta); | |
else if (yellow.isSelected()) | |
shape.setColor(Color.yellow); | |
else if (black.isSelected()) | |
shape.setColor(Color.black); | |
else if (white.isSelected()) | |
shape.setColor(Color.white); | |
else | |
shape.setColor(Color.gray); | |
shape.setDrawOutline( addBorderedShapes.isSelected() ); | |
if (addLargeShapes.isSelected()) | |
shape.reshape(3,3,100,60); | |
else | |
shape.reshape(3,3,50,30); | |
shapes.add(shape); | |
repaint(); | |
} | |
// --------------- File-related methods for opening and saving -------------------------- | |
void saveFile() { | |
File file; // The file that the user wants to save. | |
JFileChooser fd; // A file dialog that let's the user specify the file. | |
fd = new JFileChooser("."); // Open on current directory. ".." argument will open on the directory above the current one. | |
fd.setDialogTitle("Save As File..."); | |
int action = fd.showSaveDialog(this); | |
if (action != JFileChooser.APPROVE_OPTION) { | |
// User has canceled, or an error occurred. | |
return; | |
} | |
file = fd.getSelectedFile(); | |
fileName = file.getName(); | |
if (file.exists()) { | |
// If file already exists, ask before replacing it. | |
action = JOptionPane.showConfirmDialog(this, "Replace existing file?"); | |
if (action != JOptionPane.YES_OPTION) | |
return; | |
} | |
try { | |
ObjectOutputStream out = | |
new ObjectOutputStream(new FileOutputStream(file)); | |
out.writeObject(getBackground());//we first save the background color as an object | |
out.writeObject(shapes);//we then save the entire ArrayList shapes as an object. Remember that ArrayList extends Object class. | |
out.close(); | |
} | |
catch (IOException e) { | |
JOptionPane.showMessageDialog(this, | |
"Error while trying to write the file:\n" + e.getMessage()); | |
} | |
} // end saveFile() | |
void openFile() { | |
File file; // The file that the user wants to open. | |
JFileChooser fd; // A file dialog that let's the user specify the file. | |
fd = new JFileChooser("."); // Open on current directory. | |
fd.setDialogTitle("Open File..."); | |
int action = fd.showOpenDialog(this); | |
if (action != JFileChooser.APPROVE_OPTION) { | |
// User canceled the dialog, or an error occurred. | |
return; | |
} | |
file = fd.getSelectedFile(); | |
fileName = file.getName(); | |
Object obj1; // Object to be read from file. Should be a color. Because we saved the file that way. | |
Object obj2; // Second object. Should be an ArrayList of shapes. Because we saved the file that way. | |
try { | |
ObjectInputStream in = | |
new ObjectInputStream(new FileInputStream(file)); | |
obj1 = in.readObject();//obj1 now has the bgColor | |
obj2 = in.readObject();//obj2 now has the list shapes | |
in.close(); | |
} | |
catch (IOException e) { | |
JOptionPane.showMessageDialog(this, | |
"Error while trying to read the file:\n" + e.getMessage()); | |
return; | |
} | |
catch (Exception e) { | |
JOptionPane.showMessageDialog(this, | |
"Unexpected Data type found in file:\n" + e.getMessage()); | |
return; | |
} | |
try { | |
setShapes(obj1,obj2); | |
} | |
catch (IllegalArgumentException e) { | |
JOptionPane.showMessageDialog(this, | |
"File did not contain legal data for this program."); | |
} | |
} // end openFile() | |
private void setShapes(Object backgroundColor,Object newShapes) | |
throws IllegalArgumentException { | |
// Throws IllegalArgumentException if objects are not of | |
// of the correct types. | |
if (backgroundColor == null || !(backgroundColor instanceof Color)) | |
/*Note the use of the keyword instanceof | |
* Basically, you check if an object is an instance of a specific class. | |
* You normally use it, when you have a reference or parameter to an object that is of a | |
* super class or interface type and need to know whether the actual object has some other type (normally more concrete). | |
*/ | |
throw new IllegalArgumentException( | |
"Invalid data types in file."); | |
if (newShapes == null || !(newShapes instanceof ArrayList)) | |
throw new IllegalArgumentException( | |
"Invalid data type. Expecting list of shapes."); | |
ArrayList v = (ArrayList)newShapes; | |
for (int i = 0; i < v.size(); i ++) | |
if (!(v.get(i) instanceof Shape)) | |
//if v.get(i) is not a valid shape, it is invalid. Therefore, throw exception. | |
throw new IllegalArgumentException("Invalid data type in shape list."); | |
shapes = v; | |
setBackground((Color)backgroundColor); | |
} | |
// -------------------- This rest of this class implements dragging ---------------------- | |
Shape clickedShape = null; // This is the shape that the user clicks on. | |
// It becomes the draggedShape if the user is | |
// dragging, unless the user is invoking a | |
// pop-up menu. This variable is used in | |
// actionPerformed() when a command from the | |
// pop-up menu is processed. | |
Shape draggedShape = null; // This is null unless a shape is being dragged. | |
// A non-null value is used as a signal that dragging | |
// is in progress, as well as indicating which shape | |
// is being dragged. | |
int prevDragX; // During dragging, these record the x and y coordinates of the | |
int prevDragY; // previous position of the mouse. | |
public void mousePressed(MouseEvent evt) { | |
if (draggedShape != null) { | |
// A drag operation is already in progress, so ignore this click. | |
// This might happen if the user clicks a second mouse button before | |
// releasing the first one(?). | |
return; | |
} | |
int x = evt.getX(); // x-coordinate of point where mouse was clicked | |
int y = evt.getY(); // y-coordinate of point | |
clickedShape = null; // This will be set to the clicked shape, if any. | |
for ( int i = shapes.size() - 1; i >= 0; i-- ) { | |
// Check shapes from front to back. This loop will determine which shape is clicked. | |
Shape s = (Shape)shapes.get(i); | |
if (s.containsPoint(x,y)) { | |
clickedShape = s; | |
break; | |
} | |
} | |
if (clickedShape == null) { | |
// The user did not click on a shape. | |
return; | |
} | |
else if (evt.isPopupTrigger()) //Returns whether or not this mouse event is the popup menu trigger event for the platform. | |
//Note: Popup menus are triggered differently on different systems. | |
//Therefore, isPopupTrigger should be checked in both mousePressed and mouseReleased for proper cross-platform functionality. | |
{ | |
// The user wants to see the pop-up menu | |
popup.show(this,x-10,y-2); | |
} | |
else { | |
draggedShape = clickedShape; | |
prevDragX = x; | |
prevDragY = y; | |
} | |
//Note: no repaint() is mentioned, as there are no components which are changed. | |
} | |
public void mouseDragged(MouseEvent evt) { | |
if (draggedShape == null) { | |
// User did not click a shape. There is nothing to do. | |
return; | |
} | |
int x = evt.getX(); | |
int y = evt.getY(); | |
draggedShape.moveBy(x - prevDragX, y - prevDragY); | |
prevDragX = x; | |
prevDragY = y; | |
repaint(); // redraw canvas to show shape in new position | |
} | |
public void mouseReleased(MouseEvent evt) { | |
if (draggedShape == null) { | |
// User did not click on a shape. There is nothing to do. | |
return; | |
} | |
int x = evt.getX(); | |
int y = evt.getY(); | |
if (evt.isPopupTrigger()) { | |
// Check whether the user is trying to pop up a menu. | |
// As mentioned above, this should be checked in both the mousePressed() and | |
// mouseReleased() methods for cross-platform functionality. | |
popup.show(this,x-10,y-2); | |
} | |
else { | |
draggedShape.moveBy(x - prevDragX, y - prevDragY); | |
if ( draggedShape.left >= getSize().width || draggedShape.top >= getSize().height || | |
draggedShape.left + draggedShape.width < 0 || | |
draggedShape.top + draggedShape.height < 0 ) { // shape is off-screen | |
shapes.remove(draggedShape); // remove shape from list of shapes | |
} | |
repaint(); | |
} | |
draggedShape = null; // Dragging is finished. | |
} | |
public void mouseEntered(MouseEvent evt) { } // Default methods for MouseListener and MouseMotionListener | |
public void mouseExited(MouseEvent evt) { } // They are programmed to do nothing. | |
public void mouseMoved(MouseEvent evt) { } | |
public void mouseClicked(MouseEvent evt) { } | |
} // end class ShapeCanvas | |
// ------- Nested class definitions for the abstract Shape class and three ----- | |
// -------------------- concrete subclasses of Shape. -------------------------- | |
static abstract class Shape implements Serializable { | |
// A class representing shapes that can be displayed on a ShapeCanvas. | |
// The subclasses of this class represent particular types of shapes. | |
// When a shape is first constructed, it has height and width zero | |
// and a default color of white. | |
int left, top; // Position of top left corner of rectangle that bounds this shape. | |
int width, height; // Size of the bounding rectangle. | |
Color color = Color.white; // Color of this shape. | |
boolean drawOutline; // If true, a black border is drawn on the shape | |
void reshape(int left, int top, int width, int height) { | |
// Set the position and size of this shape. | |
this.left = left; | |
this.top = top; | |
this.width = width; | |
this.height = height; | |
} | |
void setSize(int width, int height) { | |
// Set the size of this shape | |
this.width = width; | |
this.height = height; | |
} | |
void moveBy(int dx, int dy) { | |
// Move the shape by dx pixels horizontally and dy pixels vertically | |
// (by changing the position of the top-left corner of the shape). | |
left += dx; | |
top += dy; | |
} | |
void setColor(Color color) { | |
// Set the color of this shape | |
this.color = color; | |
} | |
void setDrawOutline(boolean draw) { | |
// If true, a black outline is drawn around this shape. | |
drawOutline = draw; | |
} | |
boolean containsPoint(int x, int y) { | |
// Check whether the shape contains the point (x,y). | |
// This method should be | |
// overridden by a subclass if the default behavior is not | |
// appropriate for the subclass. | |
if (x >= left && x < left+width && y >= top && y < top+height) | |
return true; | |
else | |
return false; | |
} | |
abstract void draw(Graphics g); | |
// Draw the shape in the graphics context g. | |
// This must be overridden in any concrete subclass. | |
} // end of class Shape | |
static class RectShape extends Shape { | |
// This class represents rectangle shapes. | |
void draw(Graphics g) { | |
g.setColor(color); | |
g.fillRect(left,top,width,height); | |
if (drawOutline) { | |
g.setColor(Color.black); | |
g.drawRect(left,top,width,height); | |
} | |
} | |
} | |
static class OvalShape extends Shape { | |
// This class represents oval shapes. | |
void draw(Graphics g) { | |
g.setColor(color); | |
g.fillOval(left,top,width,height); | |
if (drawOutline) { | |
g.setColor(Color.black); | |
g.drawOval(left,top,width,height); | |
} | |
} | |
boolean containsPoint(int x, int y) { | |
// Check whether (x,y) is inside this oval, using the | |
// mathematical equation of an ellipse. | |
double rx = width/2.0; // horizontal radius of ellipse | |
double ry = height/2.0; // vertical radius of ellipse | |
double cx = left + rx; // x-coord of center of ellipse | |
double cy = top + ry; // y-coord of center of ellipse | |
if ( (ry*(x-cx))*(ry*(x-cx)) + (rx*(y-cy))*(rx*(y-cy)) <= rx*rx*ry*ry ) | |
return true; | |
else | |
return false; | |
} | |
} | |
static class RoundRectShape extends Shape { | |
// This class represents rectangle shapes with rounded corners. | |
// (Note that it uses the inherited version of the | |
// containsPoint(x,y) method, even though that is not perfectly | |
// accurate when (x,y) is near one of the corners.) | |
void draw(Graphics g) { | |
g.setColor(color); | |
g.fillRoundRect(left,top,width,height,width/3,height/3); | |
if (drawOutline) { | |
g.setColor(Color.black); | |
g.drawRoundRect(left,top,width,height,width/3,height/3); | |
} | |
} | |
} | |
} // end class ShapeDrawFrame |
BUGS AND HOW THEY ARE SOLVED:
Now we will show how the 3 bugs mentioned in Paint Brush Applet are solved.
- The shapes that are added do not now disappear when paint() is called again (implicitely and explicitely). This is because all shapes are stored in an ArrayList of the name "shapes". The paint function simply draws all the shapes in the list again, thus losing none!
- File Handling concepts are used to store and open files. Note that the files thus created do not have any extensions like .jpg, etc. and are thus read by the Windows System as of the type "file". It cannot be rendered effectively by any application other than this applet. Results may/may not be different in Linux-based systems because of its "Everything is a file" policy.
- The "drawing area" is defined separately and does not include the menu bar, thus solving this error.