Scroll Panes
Home ] Up ] Scroll Bars ] [ Scroll Panes ]

 

 

A more common use for scrolling is to scroll a large area in a small window.   

For example:

package swingExamples;

import java.awt.Adjustable;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;

import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;

class PanelScrollerPanel extends JPanel 
{
  public PanelScrollerPanel()
  {
    // Set up the mouse event handling
    MouseHandler handler = new MouseHandler();
    addMouseListener(handler);
    addMouseMotionListener(handler);
  }
  
  /**
   *   Adds a new square at x, y
   */
  public void add(int x, int y)
  {
    m_squares.add( new Point(x, y) );
    repaint();
  }
  
  /**
   * Finds the square that corresponds to the 
   * coordinates x,y.  If there is no square at 
   * these coordinates, returns null;
   */
  public Point find(int x, int y)
  {
    for (Point point : m_squares)
    {
      // Do these coordinates match somewhere
      // within this square?
      int xlo = point.x - SQUARE_LENGTH / 2;
      int xhi = point.x + SQUARE_LENGTH / 2;
      int ylo = point.y - SQUARE_LENGTH / 2;
      int yhi = point.y + SQUARE_LENGTH / 2;
      if ( (xlo <= x) && (x <= xhi)
        && (ylo <= y) && (y <= yhi)
      )
        return point; // Yes
    }
    return null; // No match
  }
  
  /**
   *   Removes the specified square.
   */
  public void remove(Point point)
  {
    if (point != null)
    {
      m_squares.remove(point);
      repaint();
    }
  }
  
  /**
   *   Stores scroll offsets, and then repaints.
   */
  public void translate(int x, int y)
  {
    m_dx = x;
    m_dy = y;
    repaint();
  }
  
  /**
   * Paints the panel, drawing the current 
   * set of squares.
   */
  public void paintComponent(Graphics g)
  {
    super.paintComponent(g);
    // Translate to appropriate coordinates
    g.translate(-m_dx, -m_dy);
    // Draw the outer rectangle in red.
    g.setColor(Color.RED);
    g.drawRect(0, 0, MAX_WIDTH - 1, MAX_HEIGHT - 1);
    // Draw each square
    g.setColor(Color.BLACK);
    for (Point square : m_squares)
    {
      draw(g, square);
    }
  }
  
  /**
   *   Draws the ith square in the Graphics context.
   */
  private void draw(Graphics g, Point square)
  {
    g.drawRect(square.x - SQUARE_LENGTH / 2,
               square.y - SQUARE_LENGTH / 2,
               SQUARE_LENGTH, SQUARE_LENGTH);
  }
  
  ////// Private data //////
  
  // The maximum size of the area
  // (mouse clicks outside this area have no effect)
  static final int MAX_WIDTH = 300;
  static final int MAX_HEIGHT = 200;
  
  private static final int SQUARE_LENGTH = 10; 
                            // Size of a square
  
  // The set of squares
  private ArrayList<Point> m_squares = 
                          new ArrayList<Point>();
  // Scroll offsets.
  private int m_dx = 0;
  private int m_dy = 0;
  
  //////// Inner classes //////
  
  /**
   * Hamdler for mouse events and mouse motion.
   */
  class MouseHandler extends MouseAdapter
  {
    ///// MouseListener required methods

    /**
     * If the mouse was pressed outside an 
     * existing square, adds a new square at 
     * these coordinates.
     */
    public void mousePressed(MouseEvent evt)
    {
      int x = evt.getX() + m_dx;
      int y = evt.getY() + m_dy;
      Point point = find(x, y);
      if (point == null)
      {
        // Not inside an existing square, 
        // so add a square to the panel
        if ( (x < MAX_WIDTH) && (y < MAX_HEIGHT))
        {
          add(x, y);
        }
      }
    }

    /**
     * If the mouse double-clicks on a aquare, 
     * removes the square.
     */
    public void mouseClicked(MouseEvent evt)
    {
      if (evt.getClickCount() >= 2)
      {
        int x = evt.getX();
        int y = evt.getY();
        remove( find(x, y) );
      }
    }

    ///// MouseMotionListener required methods
  
    /**
     * Causes the mouse cursor to change to a 
     * crosshairs when over a square, and to a
     * normal cursor when not.
     */
    public void mouseMoved(MouseEvent evt)
    {
      int x = evt.getX();
      int y = evt.getY();
      Cursor cursor = null;
      if (find(x, y) != null)
      {
        cursor = Cursor.getPredefinedCursor(
                          Cursor.CROSSHAIR_CURSOR);
      }
      else
      {
        cursor = Cursor.getDefaultCursor();
      }
      setCursor(cursor);
    }

    /**
     * When the mouse is over a square, 
     * and is dragged, moves the square with it.
     */
    public void mouseDragged(MouseEvent evt)
    {
      int x = evt.getX();
      int y = evt.getY();
      // Find the corresponding square
      Point square = find(x, y);
      if (square != null)
      {
        Graphics g = getGraphics();
        g.setXORMode(getBackground());
        draw(g, square);
        square.x = x;
        square.y = y;
        draw(g, square);
        g.dispose();
      }
    }    
  }
}

class PanelScrollerFrame extends JFrame 
    implements AdjustmentListener
{
  public PanelScrollerFrame()
  {
    setTitle("PanelScroller");
    setSize(300, 200);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    Container contentPane = getContentPane();
    contentPane.add(m_panel, BorderLayout.CENTER);
    
    // Add the vertical scrollbar to the east
    contentPane.add(
        m_verticalScroller, BorderLayout.EAST);
    m_verticalScroller.addAdjustmentListener(this);
    m_verticalScroller.setValues(
        m_verticalScroller.getValue(),
        0, 0, PanelScrollerPanel.MAX_HEIGHT);
    
    // Add the horizontal scrollbar to the south
    contentPane.add(
        m_horizontalScroller, BorderLayout.SOUTH);
    m_horizontalScroller.addAdjustmentListener(this);
    m_horizontalScroller.setValues(
        m_horizontalScroller.getValue(),
        0, 0, PanelScrollerPanel.MAX_WIDTH);
    
    // Add a component listener to the frame,
    // to cause the scrollbars to display correctly 
    // on show and resize.
    addComponentListener( new ComponentAdapter()
      {
        public void componentShown(ComponentEvent evt)
        {
          setVisibleAmounts();
        }

        public void componentResized(ComponentEvent evt)
        {
          setVisibleAmounts();
        }
      }
    );
  }
  
  public void adjustmentValueChanged(AdjustmentEvent evt)
  {
    m_panel.translate(
        m_horizontalScroller.getValue(),
        m_verticalScroller.getValue());
  }
  
  private void setVisibleAmounts()
  {
    Dimension dim = m_panel.getSize();
    m_horizontalScroller.setVisibleAmount(dim.width);
    m_verticalScroller.setVisibleAmount(dim.height);
  }
  
  ///// Private data /////
  private PanelScrollerPanel m_panel = 
      new PanelScrollerPanel();
  private JScrollBar m_horizontalScroller =
      new JScrollBar(Adjustable.HORIZONTAL);
  private JScrollBar m_verticalScroller =
      new JScrollBar(Adjustable.VERTICAL);
}

public class PanelScroller
{
  public static void main(String[] args)
  {
    PanelScrollerFrame frame = new PanelScrollerFrame();
    frame.setVisible(true);
  }
}

which produces:

and when the window is expanded:

Notice that there are no squares outside the red rectangular area. This is because the scrollbars are defined only on that area.  This results in mouse clicks not having any effect outside the red rectangular area.

 

This page was last modified on 02 October, 2007