FileDocCategorySizeDatePackage
ScrollableScribble.javaAPI DocExample5680Thu Aug 08 12:23:38 BST 1996None

ScrollableScribble.java

// This example is from the book _Java in a Nutshell_ by David Flanagan.
// Written by David Flanagan.  Copyright (c) 1996 O'Reilly & Associates.
// You may study, use, modify, and distribute this example for any purpose.
// This example is provided WITHOUT WARRANTY either expressed or implied.

import java.awt.*;

public class ScrollableScribble extends Panel {
    Canvas canvas;
    Scrollbar hbar, vbar;
    java.util.Vector lines = new java.util.Vector(100, 100);
    int last_x, last_y;
    int offset_x, offset_y;
    int canvas_width, canvas_height;
    
    // Create a canvas and two scrollbars and lay them out in the panel.
    // Use a BorderLayout to get the scrollbars flush against the 
    // right and bottom sides of the canvas.  When the panel grows,
    // the canvas and scrollbars will also grow appropriately.
    public ScrollableScribble() {
        // implicit super() call here creates the panel
        canvas = (Canvas) new BlankCanvas();
        hbar = new Scrollbar(Scrollbar.HORIZONTAL);
        vbar = new Scrollbar(Scrollbar.VERTICAL);
        this.setLayout(new BorderLayout(0, 0));
        this.add("Center", canvas);
        this.add("South", hbar);
        this.add("East", vbar);
    }
    
    // Draw the scribbles that we've saved in the Vector.
    // This method will only ever be invoked when the BlankCanvas
    // class (below) calls it.  It uses the Graphics object from the 
    // BlankCanvas object, and the Vector of lines from this class
    // to redraw everything.  
    // The offset_x and offset_y variables specify which portion of
    // the larger (1000x1000) scribble is to be displayed in the 
    // relatively small canvas.  Moving the scrollbars changes these
    // variables, and thus scrolls the picture.  Note that the Graphics
    // object automatically does clipping; we can't accidentally 
    // draw outside of the borders of the BlankCanvas.
    public void paint(Graphics g) {
        Line l;
        for(int i = 0; i < lines.size(); i++) {
            l = (Line)lines.elementAt(i);
            g.drawLine(l.x1 - offset_x, l.y1 - offset_y, 
                      l.x2 - offset_x, l.y2 - offset_y);
        }
    }
    
    // Handle user's mouse scribbles.  Draw the scribbles
    // and save them in the vector for later redrawing.
    // Note that to draw these scribbles, we have to look up the
    // Graphics object of the canvas.
    public boolean mouseDown(Event e, int x, int y)
    {
        last_x = x; last_y = y;
        return true;
    }
    public boolean mouseDrag(Event e, int x, int y)
    {
        Graphics g = canvas.getGraphics();
        g.drawLine(last_x, last_y, x, y);
        lines.addElement(new Line(last_x + offset_x, last_y + offset_y, 
                      x + offset_x, y + offset_y));
        last_x = x;
        last_y = y;
        return true;
    }
    // handle mouse up, too,, just for symmetry.
    public boolean mouseUp(Event e, int x, int y) {  return true; }
    
    // This method handles the scrollbar events.  It updates the
    // offset_x and offset_y variables that are used by the paint()
    // method, and then calls update(), which clears the canvas and
    // invokes the paint() method to redraw the scribbles.
    public boolean handleEvent(Event e) {
        if (e.target == hbar) {
            switch(e.id) {
            case Event.SCROLL_LINE_UP:  
            case Event.SCROLL_LINE_DOWN: 
            case Event.SCROLL_PAGE_UP:  
            case Event.SCROLL_PAGE_DOWN: 
            case Event.SCROLL_ABSOLUTE:  
                offset_x = ((Integer)e.arg).intValue();    break;
            }
            this.update(canvas.getGraphics());
            return true;
        }
        else if (e.target == vbar) {
            switch(e.id) {
            case Event.SCROLL_LINE_UP:  
            case Event.SCROLL_PAGE_UP:  
            case Event.SCROLL_LINE_DOWN: 
            case Event.SCROLL_PAGE_DOWN: 
            case Event.SCROLL_ABSOLUTE:  
                offset_y = ((Integer)e.arg).intValue();    break;
            }
            this.update(canvas.getGraphics());
            return true;
        }
        
        // If we didn't handle it above, pass it on to the superclass
        // handleEvent routine, which will check its type and call
        // the mouseDown(), mouseDrag(), and other methods.
        return super.handleEvent(e);
    }

    // This method is called when our size is changed.  We need to
    // know this so we can update the scrollbars
    public synchronized void reshape(int x, int y, int width, int height) {
        // do the real stuff
        super.reshape(x, y, width, height);
        // Update our scrollbar page size
        Dimension hbar_size = hbar.size();
        Dimension vbar_size = vbar.size();
        canvas_width = width - vbar_size.width;
        canvas_height = height - hbar_size.height;
        hbar.setValues(offset_x, canvas_width, 0, 1000-canvas_width);
        vbar.setValues(offset_y, canvas_height, 0, 1000-canvas_height);
        hbar.setPageIncrement(canvas_width/2);
        vbar.setPageIncrement(canvas_height/2);
        this.update(canvas.getGraphics());
        
    }
}

// This class stores the coordinates of one line of the scribble.
class Line {
    public int x1, y1, x2, y2;
    public Line(int x1, int y1, int x2, int y2) {
        this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2;
    }
}

// This class is a trivial subclass of Canvas.  All it knows how to do
// is ask its parent (the ScrollableScribble object) for a redraw.
class BlankCanvas extends Canvas {
    public void paint(Graphics g) {
        this.getParent().paint(g);
    }
}