// 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); } }