This week is another fairly short lab. It will give you the opportunity to work with the BufferedImage class. The program that you write was inspired by one of the features in an old children's graphics program named KidPix.
Labs 11 and 12 are both due at noon on Wednesday. Please be sure that they are in your CVS repository by that time. Lab 13 will be due on Wednesday of next week. Lab 13 is the last lab that will be collected and graded; next week, you will be given some points for coming to lab and working on your final project.
Start a new Eclipse project for Lab 13. You will need several image files in your project. You can find some in the directory /classes/f07/cs225/files_for_lab_13. You can copy these into your project.
To begin, you can create a subclass of JPanel that simply displays a given image. Store the image in a member variable named (for example) image, of type BufferedImage. Your class should have a constructor that takes a variable of type BufferedImage as a parameter. It should save that parameter in the instance variable, image. Furthermore, the preferred size of the panel should be the same as the size of the image, so the constructor should call
setPreferredSize( new Dimension( image.getWidth(), image.getHeight() ) );
Your class will also need a paintComponent method that simply copies the image to the screen:
public void paintComponent(Graphics g) { g.drawImage(image, 0, 0, null); }
Next, create a window to hold your panel. Make a subclass of the JFrame class. In the constructor, read in one of the image files that you added to your project. These files are "resources" for the program and can be loaded using the usual technique for loading resources. For example, with imageName as the name of the image file resource:
URL imageURL = this.getClass().getClassLoader().getResource(imageName); BufferedImage image = null; try { image = ImageIO.read(imageURL); } catch (Exception e) { JOptionPane.showMessageDialog(null, "Sorry, can't load image.\nExiting program."); System.exit(1); }
(It would be nice to choose the image name at random from among the available images.)
Once you have the image, you can use it to construct an object belonging to your JPanel class. Call setContentPane(panel) to install your panel in the window. Don't forget to call pack() to set the size of the window to match the size of the panel. Call setVisible(true) to make the window visible on the screen.
You will need a main program to create a window and show it on the screen. You can put the main() method in your JFrame class; it just has to create the window object.
Before proceeding, make sure that your program works so far.
Now, to add the main functionality of the program. When the program first starts up, the window should show a blank gray area. As the user drags the mouse in the window, the gray should be erased, revealing the image that lies behind the gray "mask."
To implement this, you will need a second image. Add another BufferedImage member variable, named (for example) mask, to your JPanel class. In the constructor, create the second image using
mask = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Fill the mask image with a gray color, using mask.getGraphics() to get a graphics context for drawing, as covered both in class and in the book. (If you prefer and if you have time, you could fill the mask with a fancy checkerboard pattern.)
Add a second drawImage command to the paintComponent() method, to draw the mask over the image. At this point, when your run the program, you should see only the mask in the window.
To finish the program, you have to implement mouse events. You should declare that your class "implements MouseListener, MouseMotionListener". Add the methods required by these interfaces. (Eclipse can do this for you!)
The mousePressed() and mouseDragged() methods should be defined to clear a small rectangle in the mask at the mouse position. You want to make that rectangle transparent. This is something that you can do in a BufferedImage of type TYPE_INT_ARGB. The following method will clear a square of size brushSize in the mask, centered at the point (x,y), making that rectangle transparent:
private void clear(int x, int y, int brushSize) { Graphics2D maskGraphics = mask.createGraphics(); maskGraphics.setBackground(new Color(0,0,0,0)); maskGraphics.clearRect(x - brushSize/2, y - brushSize/2, brushSize, brushSize); maskGraphics.dispose(); }
Don't forget to call repaint() to make the change appear on the screen!
Once you've done this, your program should be complete. Dragging the mouse in the window should reveal the image below!