ScrollPane

A ScrollPane is a Container with built-in scrollbars that can be used to scroll its contents. In the current implementation, a ScrollPane can hold only one Component and has no layout manager. The component within a ScrollPane is always given its preferred size. While the scrollpane's inability to hold multiple components sounds like a deficiency, it isn't; there's no reason you can't put a Panel inside a ScrollPane, put as many components as you like inside the Panel, and give the Panel any layout manager you wish.

Scrolling is handled by the ScrollPane peer, so processing is extremely fast. In Example 11.1, the user moves a Scrollbar to trigger a scrolling event, and the peer sends the event to the Java program to find someone to deal with it. Once it identifies the target, it posts the event, then tries to find a handler. Eventually, the applet's handleEvent() method is called to reposition the ImageCanvas. The new position is then given to the peer, which finally redisplays the Canvas. Although most of the real work is behind the scenes, it is still happening. With ScrollPane, the peer generates and handles the event itself, which is much more efficient.

ScrollPane Methods

Constants

The ScrollPane class contains three constants that can be used to control its scrollbar display policy. The constants are fairly self-explanatory. The constants are used in the constructor for a ScrollPane instance.

Constructors Layout methods Scrolling methods Miscellaneous methods
java.awt.ScrollPane[scrollpane0,0,0,0x0,invalid,ScrollPosition=(0,0), Insets=(0,0,0,0),ScrollbarDisplayPolicy=always] 

ScrollPane Events

The ScrollPane peer deals with the scrolling events for you. It is not necessary to catch or listen for these events. As with any other Container, you can handle the 1.0 events of the object you contain or listen for 1.1 events that happen within you.

Using a ScrollPane

The following applet demonstrates one way to use a ScrollPane. Basically, you place the object you want to scroll in the ScrollPane by calling the add() method. This can be a Panel with many objects on it or a Canvas with an image drawn on it. You then add as many objects as you want to the Panel or scribble on the Canvas to your heart's delight. No scrolling event handling is necessary. That is all there is to it. To make this example a little more interesting, whenever you select a button, the ScrollPane scrolls to a randomly selected position. Figure 11.4 displays the screen.

Figure 11.4: A ScrollPane containing many buttons

[Graphic: Figure 11-4]

Here's the code:

// Java 1.1 only import java.awt.*; import java.awt.event.*; import java.applet.*;
public class scroll extends Applet implements ActionListener, ContainerListener {
 ScrollPane sp = new ScrollPane (ScrollPane.SCROLLBARS_ALWAYS);
public void init () {
 setLayout (new BorderLayout ()); Panel p = new Panel(new GridLayout (7, 8)); p.addContainerListener (this);
for (int j=0;j<50;j++) p.add (new Button ("Button-" + j)); sp.add (p); add (sp, "Center");
}
public void componentAdded(ContainerEvent e) {
 if (e.getID() == ContainerEvent.COMPONENT_ADDED) {
 if (e.getChild() instanceof Button) {
 Button b = (Button)e.getChild(); b.addActionListener(this);
}
}
}
public void componentRemoved(ContainerEvent e) {
}
public void actionPerformed (ActionEvent e) {
 Component c = sp.getComponent(); Dimension d = c.getSize(); sp.setScrollPosition ((int)(Math.random()*d.width), (int)(Math.random()*d.height));
}
} 

Working with the ScrollPane itself is easy; we just create one, add a Panel to it, set the Panel's layout manager to GridLayout, and add a lot of buttons to the Panel. The applet itself is the action listener for all the buttons; when anybody clicks a button, actionPerformed() is called, which generates a new random position based on the viewport size and sets the new scrolling position accordingly by calling setScrollPosition().

The more interesting part of this applet is the way it works with buttons. Instead of directly adding a listener for each button, we add a ContainerListener to the containing panel and let it add listeners. Although this may seem like extra work here, it demonstrates how you can use container events to take actions whenever someone adds or removes a component. At first glance, you might ask why I didn't just call enableEvents(AWTEvent.CONTAINER_EVENT_MASK) and override the applet's processContainerEvent() to attach the listeners. If we were only adding our components to the applet, that would work great. Unfortunately, the applet is not notified when buttons are added to an unrelated panel. It would be notified only when the panel was added to the applet.