FileDocCategorySizeDatePackage
SerializedScribble.javaAPI DocExample8688Mon Sep 22 13:30:32 BST 1997None

SerializedScribble.java

// This example is from _Java Examples in a Nutshell_. (http://www.oreilly.com)
// Copyright (c) 1997 by David Flanagan
// This example is provided WITHOUT ANY WARRANTY either expressed or implied.
// You may study, use, modify, and distribute it for non-commercial purposes.
// For any commercial use, see http://www.davidflanagan.com/javaexamples

import java.awt.*;               // ScrollPane, PopupMenu, MenuShortcut, etc.
import java.awt.event.*;         // New event model.
import java.io.*;                // Object serialization streams.
import java.util.zip.*;          // Data compression/decompression streams.
import java.util.Vector;         // To store the scribble in.

/**
 * This class demonstrates the use of object serialization to provide
 * a file format for saving application state.  It saves a user's scribbles
 * as a compressed, serialized Vector of Line objects.
 **/
public class SerializedScribble extends Frame {
  /** A very simple main() method for our program. */
  public static void main(String[] args) { new SerializedScribble(); }

  /** Create a Frame, Menu, and Scribble component */
  public SerializedScribble() {
    super("SerialziedScribble");             // Create the window.

    final Scribble scribble;
    scribble = new Scribble(this, 300, 300); // Create a bigger scribble area.
    this.add(scribble, "Center");            // Add it to the ScrollPane.

    MenuBar menubar = new MenuBar();         // Create a menubar.
    this.setMenuBar(menubar);                // Add it to the frame.
    Menu file = new Menu("File");            // Create a File menu.
    menubar.add(file);                       // Add to menubar.

    // Create three menu items, with menu shortcuts, and add to the menu.
    MenuItem load, save, quit;
    file.add(load = new MenuItem("Load"));
    file.add(save = new MenuItem("Save"));
    file.addSeparator();                     // Put a separator in the menu
    file.add(quit = new MenuItem("Quit"));

    // Create and register action listener objects for the three menu items.
    load.addActionListener(new ActionListener() {     // Open a new window
      public void actionPerformed(ActionEvent e) { scribble.load(); }
    });
    save.addActionListener(new ActionListener() {     // Close this window.
      public void actionPerformed(ActionEvent e) { scribble.save(); }
    });
    quit.addActionListener(new ActionListener() {     // Quit the program.
      public void actionPerformed(ActionEvent e) { System.exit(0); }
    });

    // Another event listener, this one to handle window close requests.
    this.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) { System.exit(0); }
    });

    // Set the window size and pop it up.
    this.pack();
    this.show();
  }

  /**
   * This class is a custom component that supports scribbling.  Note that 
   * it extends Component rather than Canvas, making it "lightweight."
   **/
  static class Scribble extends Component {
    protected short last_x, last_y;               // Coordinates of last click.
    protected Vector lines = new Vector(256,256); // Store the scribbles.
    protected int width, height;                  // The preferred size.
    protected Frame frame;                        // The frame we are within.
    
    /** This constructor requires a Frame and a desired size */
    public Scribble(Frame frame, int width, int height) {
      this.frame = frame;
      this.width = width;
      this.height = height;
      
      // We handle scribbling with low-level events, so we must specify
      // which events we are interested in.
      this.enableEvents(AWTEvent.MOUSE_EVENT_MASK);
      this.enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
    }
    
    /** 
     * Specifies big the component would like to be.  It always returns the
     * preferred size passed to the Scribble() constructor 
     **/
    public Dimension getPreferredSize() {return new Dimension(width, height);}
    
    /** Draw all the saved lines of the scribble */
    public void paint(Graphics g) {
      for(int i = 0; i < lines.size(); i++) {
        Line l = (Line)lines.elementAt(i);
        g.drawLine(l.x1, l.y1, l.x2, l.y2);
      }
    }
    
    /**
     * This is the low-level event-handling method called on mouse events
     * that do not involve mouse motion.
     **/
    public void processMouseEvent(MouseEvent e) {
      if (e.getID() == MouseEvent.MOUSE_PRESSED) {
        last_x = (short)e.getX(); last_y = (short)e.getY(); // Save position.
      }
      else super.processMouseEvent(e);  // Pass other event types on.
    }
    
    /**
     * This method is called for mouse motion events.  It adds a line to the
     * scribble, on screen, and in the saved representation
     **/
    public void processMouseMotionEvent(MouseEvent e) {
      if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
        Graphics g = getGraphics();                     // Object to draw with.
        g.drawLine(last_x, last_y, e.getX(), e.getY()); // Draw this line
        lines.addElement(new Line(last_x, last_y,       // and save it, too.
                                  (short) e.getX(), (short)e.getY()));
        last_x = (short) e.getX();  // Remember current mouse coordinates.
        last_y = (short) e.getY();
      }
      else super.processMouseMotionEvent(e);  // Important!
    }
    
    /**
     * Prompt the user for a filename, and save the scribble in that file.
     * Serialize the vector of lines with an ObjectOutputStream.
     * Compress the serialized objects with a GZIPOutputStream.
     * Write the compressed, serialized data to a file with a FileOutputStream.
     * Don't forget to flush and close the stream.
     **/
    public void save() {
      // Create a file dialog to query the user for a filename.
      FileDialog f = new FileDialog(frame, "Save Scribble", FileDialog.SAVE);
      f.show();                        // Display the dialog and block.
      String filename = f.getFile();   // Get the user's response
      if (filename != null) {          // If user didn't click "Cancel".
        try {
          // Create the necessary output streams to save the scribble.
          FileOutputStream fos = new FileOutputStream(filename);// Save to file
          GZIPOutputStream gzos = new GZIPOutputStream(fos);    // Compressed
          ObjectOutputStream out = new ObjectOutputStream(gzos);// Save objects
          out.writeObject(lines);      // Write the entire Vector of scribbles
          out.flush();                 // Always flush the output.
          out.close();                 // And close the stream.
        }
        // Print out exceptions.  We should really display them in a dialog...
        catch (IOException e) { System.out.println(e); }
      }
    }
    
    /**
     * Prompt for a filename, and load a scribble from that file.
     * Read compressed, serialized data with a FileInputStream.
     * Uncompress that data with a GZIPInputStream.
     * Deserialize the vector of lines with a ObjectInputStream.
     * Replace current data with new data, and redraw everything.
     **/
    public void load() {
      // Create a file dialog to query the user for a filename.
      FileDialog f = new FileDialog(frame, "Load Scribble", FileDialog.LOAD);
      f.show();                         // Display the dialog and block.
      String filename = f.getFile();    // Get the user's response
      if (filename != null) {           // If user didn't click "Cancel".
        try {
          // Create necessary input streams
          FileInputStream fis = new FileInputStream(filename);// Read from file
          GZIPInputStream gzis = new GZIPInputStream(fis);    // Uncompress
          ObjectInputStream in = new ObjectInputStream(gzis); // Read objects
          // Read in an object.  It should be a vector of scribbles
          Vector newlines = (Vector)in.readObject();
          in.close();                    // Close the stream.
          lines = newlines;              // Set the Vector of lines.
          repaint();                     // And redisplay the scribble.
        }
        // Print out exceptions.  We should really display them in a dialog...
        catch (Exception e) { System.out.println(e); }
      }
    }
    
    /** 
     * A class to store the coordinates of one scribbled line.
     * The complete scribble is stored as a Vector of these objects 
     **/
    static class Line implements Serializable {
      public short x1, y1, x2, y2;
      public Line(short x1, short y1, short x2, short y2) {
        this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2;
      }
    }
  }
}