11.2 The JScrollPane Class


The JScrollPane class offers a more flexible version of the ScrollPane class found in the AWT package. Beyond the automatic scrollbars, you can put in horizontal and vertical headers as well as active components in the corners of your pane. (Figure 11-6 shows the exact areas available in a JScrollPane, which is managed by the ScrollPaneLayout class.)

Many Swing components use JScrollPane to handle their scrolling. The JList component, for example, does not handle scrolling on its own. Instead, it concentrates on presenting the list and making selection easy, assuming you'll put it inside a JScrollPane if you need scrolling. Figure 11-3 shows a simple JScrollPane in action with a JList object.

Figure 11-3. JScrollPane showing two portions of a list that is too long for one screen
figs/swng2.1103.gif

This particular example does not take advantage of the row or column headers. The scrollpane adds the scrollbars automatically, but only "as needed." If we were to resize the window to make it much larger, the scrollbars would become inactive. Here's the code that builds this pane:

// ScrollList.java // A simple JScrollPane // import javax.swing.*; import java.awt.*; public class ScrollList extends JFrame {   JScrollPane scrollpane;   public ScrollList( ) {     super("JScrollPane Demonstration");     setSize(300, 200);     setDefaultCloseOperation(EXIT_ON_CLOSE);     String categories[] = { "Household", "Office", "Extended Family",                             "Company (US)", "Company (World)", "Team",                             "Will", "Birthday Card List", "High School",                             "Country", "Continent", "Planet" };     JList list = new JList(categories);     scrollpane = new JScrollPane(list);     getContentPane( ).add(scrollpane, BorderLayout.CENTER);   }   public static void main(String args[]) {     ScrollList sl = new ScrollList( );     sl.setVisible(true);   } }

A similar technique can be used with many of the Swing components, including JPanel, JTree, JTable, and JTextArea. Chapter 15 discusses the JTable class and its particular use of JScrollPane.

While you will certainly use JScrollPane with many of the Swing components, you can also build your own components and drop them into a scrollable area. You may bundle up a piece of your user interface into one panel and make that panel scrollable.

Here's a short example that takes the items from our previous list and turns them into a basic census form. As you can see in Figure 11-4, the form itself is a panel with a size of 600 x 400 pixels. We display it inside a JScrollPane and make the application 300 x 200.

Figure 11-4. A JScrollPane with a component larger than the application window
figs/swng2.1104.gif

The only change from our first program is that we now have to build the census panel from scratch. We build a JPanel containing various labels and radio buttons, and slap it into a JScrollPane. The only logic involved is figuring out whether we're adding a label or a button, and getting the buttons into appropriate ButtonGroups (one group per row).

// ScrollDemo.java // A simple JScrollPane demonstration // import javax.swing.*; import java.awt.*; import java.awt.event.*; public class ScrollDemo extends JFrame {   JScrollPane scrollpane;   public ScrollDemo( ) {     super("JScrollPane Demonstration");     setSize(300, 200);     setDefaultCloseOperation(EXIT_ON_CLOSE);     init( );     setVisible(true);   }   public void init( ) {     JRadioButton form[][] = new JRadioButton[12][5];     String counts[] = { "", "0-1", "2-5", "6-10", "11-100", "101+" };     String categories[] = { "Household", "Office", "Extended Family",                             "Company (US)", "Company (World)", "Team",                             "Will", "Birthday Card List", "High School",                             "Country", "Continent", "Planet" };     JPanel p = new JPanel( );     p.setSize(600, 400);     p.setLayout(new GridLayout(13, 6, 10, 0));     for (int row = 0; row < 13; row++) {       ButtonGroup bg = new ButtonGroup( );       for (int col = 0; col < 6; col++) {         if (row == 0) {           p.add(new JLabel(counts[col]));         }         else {           if (col == 0) {             p.add(new JLabel(categories[row - 1]));           }           else {             form[row - 1][col - 1] = new JRadioButton( );             bg.add(form[row -1][col - 1]);             p.add(form[row -1][col - 1]);          }         }       }     }     scrollpane = new JScrollPane(p);     getContentPane( ).add(scrollpane, BorderLayout.CENTER);   }   public static void main(String args[]) {     new ScrollDemo( );   } }

11.2.1 Properties

Table 11-3 shows how the JScrollPane properties grant you access to the five main components (not the corners) and the scrollbar policies. The valid values for horizontalScrollBarPolicy and verticalScrollBarPolicy are defined in the ScrollPaneConstants interface (see Table 11-8). The validateRoot property is always true to ensure that revalidation calls to any of the pane's descendants cause the scrollpane and all of its descendants to be validated, and that revalidation doesn't go any further than the JScrollPane, which would be redundant. The wheelScrollingEnabled property, added in SDK 1.4, allows you to enable or disable support for mice with a middle-wheel button.

Table 11-3. JScrollPane properties

Property

Data type

get

is

set

Default value

accessibleContexto

AccessibleContext

·

   

JScrollPane.AccessibleJScrollPane( )

columnHeaderb

JViewport

·

   

null

columnHeaderView

Component

   

·

 

componentOrientationb, o

int

·

 

·

ComponentOrientation.UNKNOWN

horizontalScrollBarb

JScrollBar

·

   

null

horizontalScrollBarPolicyb

int

·

 

·

HORIZONTAL_SCROLLBAR_AS_NEEDED

layoutb, o

LayoutManager

·

 

·

new ScrollPaneLayout( )

opaque

boolean

 

·

 

false

rowHeaderb

JViewport

·

   

null

rowHeaderView

Component

   

·

 

UI

ScrollPane-UI

·

 

·

From L&F

UIClassIDo

String

     

"ScrollPaneUI"

validateRoot

boolean

 

·

 

true

verticalScrollbarb

JScrollBar

·

   

null

verticalScrollBarPolicyb

int

·

 

·

VERTICAL_SCROLLBAR_AS_NEEDED

viewportb

JViewport

·

   

null

viewportBorderb

Border

·

 

·

null

viewportBorderBounds

Rectangle

·

     

viewportView

Component

   

·

 

wheelScrollingEnabledb, 1.4

boolean

 

·

·

true

1.4since 1.4, bbound, ooverridden

See also properties from the JComponent class (Table 3-6).

Given that you already have a viewport set up for the row and column headers, or the main viewport itself, you can use the columnHeaderView , rowHeaderView, and viewportView properties to modify the contents of these viewports. Note that the set accessors for these properties don't create new viewport objects; they simply set the view to display the given component.

11.2.2 Constructors

public JScrollPane( )
public JScrollPane(Component view)
public JScrollPane(Component view, int verticalScrollBarPolicy, int horizontalScrollBarPolicy)
public JScrollPane(int verticalScrollBarPolicy, int horizontalScrollBarPolicy)

Create new scrollpanes. You can start off by specifying the view (i.e., the component to scroll), the scrollbar policies, or both. Just make sure you get the scrollbar policies in the right order! Of course, any of these pieces can be specified or changed after the scrollpane has been created. See the setViewportView( ) method later in this chapter.

11.2.3 Pane Component Methods

public JScrollBar createHorizontalScrollBar( )
public JScrollBar createVerticalScrollBar( )

Used by the UI for the scrollpane to create the scrollbars you see. You can override these methods if you want to use a specific subclass of the JScrollBar class.

public JViewport createViewport( )

Create the JViewport object that contains the main view you see. You can override this to use your own subclass of JViewport.

public Component getCorner(String whichCorner)
public void setCorner(String whichCorner, Component corner)

Get or set the component in the corner of a scrollpane. The whichCorner argument can be any one of the corner strings from the ScrollPaneConstants class (see Table 11-4). You can add any component you like to the corners.

11.2.4 Headers and Corners

Neither of the previous examples took advantage of the additional features provided by JScrollPane over the AWT ScrollPane class. You can add headers to your scrolling panes and even put active components in the corners. Figure 11-5 shows an expanded example of our census program with headers and an "Information" button in the upper-left corner.

Figure 11-5. A JScrollPane with a button in the upper-left corner that opens a pop up
figs/swng2.1105.gif

The code to add to the init( ) method for our demo is straightforward:

    // Add in some JViewports for the column and row headers.     JViewport jv1 = new JViewport( );     jv1.setView(new JLabel(new ImageIcon("columnlabel.gif")));     scrollpane.setColumnHeader(jv1);     JViewport jv2 = new JViewport( );     jv2.setView(new JLabel(new ImageIcon("rowlabel.gif")));     scrollpane.setRowHeader(jv2);     // And throw in an information button     JButton jb1 = new JButton(new ImageIcon("question.gif"));     jb1.addActionListener(new ActionListener( ) {       public void actionPerformed(ActionEvent ae) {         JOptionPane.showMessageDialog(null,                "This is an Active Corner!", "Information",                JOptionPane.INFORMATION_MESSAGE);       }     } );     scrollpane.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, jb1);

We use a JLabel inside a JViewport for each header. The viewport in the headers allows the JScrollPane to synchronize header scrolling with the main viewport. We'll look at the JViewport class in more detail later in this chapter.

When you set up corner components, remember that if your scrollbars are on an as-needed basis, your corners could disappear. In our example, if we moved the information button to the upper-right corner and then made the window tall enough to contain the entire census form, the vertical scrollbar would disappear, and so would the Information button. You can alleviate this problem by setting the appropriate scrollbar policy to "always." That way, your corners stick around even when the scrollbars are not active.

11.2.5 The Scrollable Interface

You may have noticed that several Swing components rely on JScrollPane to do the scrolling work for them. Most of those components, like JList, seem to use the scrollpane intelligently. That's not by accident. These components implement the Scrollable interface. This interface defines five methods that a component can implement to get a natural effect out of the scrollpane. By "natural" we mean that things like the line and page increments behave the way you would expect.

A component does not need to implement Scrollable to be scrollable. Anything you add to a JScrollPane scrolls properly. The Scrollable interface merely provides some intelligence to make scrolling more convenient.

11.2.5.1 Increment methods
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)

These methods should be used to return the appropriate increment amount required to display the next logical row or column of the component, depending on the value of orientation. orientation can be either SwingConstants.HORIZONTAL or SwingConstants.VERTICAL. The unit increment specifies (in pixels) how to display the next logical row or column; the block increment (also pixels) specifies how to "page" horizontally or vertically. The current position of the component is determined by visibleRect. The direction argument has a positive (> 0) value for moving down or right and a negative value (< 0) for moving up or left.

11.2.5.2 Viewport dimension methods

The other methods of the interface dictate the relation between the visible area of the scrollable component and the viewport it is displayed in:

public Dimension getPreferredScrollableViewportSize( )

This method should return the preferred size of the viewport containing the component. This value may or may not be the same as the value returned by getPreferredSize( ) for the component. If you recall JList, you'll realize that the preferred size of the component itself is a dimension big enough to display all of the items in the list. The preferred size for the viewport, however, would only be big enough to display some particular number of rows in the list.

public boolean getScrollableTracksViewportHeight( )
public boolean getScrollableTracksViewportWidth( )

These methods can be used to effectively disable horizontal or vertical scrolling in a scrollpane. If you return true for either of these methods, you force the component's height (or width) to match that of its containing viewport. An example might be a text area component that supports word wrapping. Since the text will wrap regardless of the width of the component, you could have getScrollableTracksViewportWidth( ) return true. As the scrollpane is resized, the vertical scrollbar still moves up and down through the text, but the horizontal scrollbar is not used. Returning false, then, indicates that the component's height (or width) is determined irrespective of the viewport's dimensions. A scrollpane might then display a scrollbar to allow the user to view the entire component.

11.2.5.3 The JScrollPane.ScrollBar class
protected class JScrollPane.ScrollBar extends JScrollBar implements UIResource

By default, the scrollbars used in a JScrollPane are instances of this class. These scrollbars are a bit smarter than regular scrollbars. They check with the view to see if it implements the Scrollable interface. If it does (and if you did not explicitly set the unit and block increments), then these scrollbars ask the view to provide what it thinks are the appropriate values.

11.2.6 The ScrollPaneLayout Class

The JScrollPane class is actually just a panel with a hard-working layout manager and some convenient access methods for the manager. While you probably will not use this class on its own, the ScrollPaneLayout class is the manager that provides layout control for the nine areas of a JScrollPane object:

  • Viewport

  • Row header

  • Column header

  • Vertical scrollbar

  • Horizontal scrollbar

  • Four corners (upper left, upper right, lower left, and lower right)

These nine components are laid out as shown in Figure 11-6.

Figure 11-6. The layout areas managed by ScrollPaneLayout
figs/swng2.1106.gif

The column headers and scrollbars behave like the four compass positions (North, South, East, and West) of a BorderLayout-managed panel. The vertical components are as wide as they need to be and as tall as the viewport. The horizontal components are as tall as they need to be and as wide as the viewport. The difference from the BorderLayout-managed panels is that the ScrollPaneLayout panels have four corners. Each corner can be a regular component (or blank). The corners appear based on the visibility of the headers and scrollbars. For example, if both of the scrollbars are visible, the lower-right corner component would be available. The valid values for these positions are defined in the ScrollPaneConstants interface (see Table 11-4).

Table 11-4. ScrollPaneLayout constant values

Location string from ScrollPaneConstants

Component location

VIEWPORT

Main viewing area, typically a JViewport component

COLUMN_HEADER

The column header (a row), typically a JViewport component

ROW_HEADER

The row header (a column), typically a JViewport component

HORIZONTAL_SCROLLBAR

The horizontal scrollbar for the viewport; must be a JScrollBar component

VERTICAL_SCROLLBAR

The vertical scrollbar for the viewport; must be a JScrollBar component

LOWER_LEFT_CORNER

The southwest corner, typically empty

LOWER_RIGHT_CORNER

The southeast corner, typically empty

UPPER_LEFT_CORNER

The northwest corner, typically empty

UPPER_RIGHT_CORNER

The northeast corner, typically empty

The ScrollPaneLayout class also contains several methods for manipulating the scrollbars associated with the viewport (via JScrollPane's properties; see Table 11-1). Both the horizontal and vertical scrollbars have policies that determine when (and if) they show up. You can set and retrieve the scrollbar policies using these methods with constants defined in the ScrollPaneConstants interface listed in Table 11-5.

Table 11-5. ScrollPaneLayout policy constants from ScrollPaneConstants

ScrollPaneConstants constant

Type

Effect on Scrollbar component

HORIZONTAL_SCROLLBAR_ALWAYS

int

Always keeps a horizontal scrollbar around, even if the viewport extent area is wide enough to display the entire component

HORIZONTAL_SCROLLBAR_AS_NEEDED

int

Shows a horizontal scrollbar whenever the extent area is smaller than the full component

HORIZONTAL_SCROLLBAR_NEVER

int

Never shows a horizontal scrollbar, even if the component is wider than the viewport extent area

VERTICAL_SCROLLBAR_ALWAYS

int

Always keeps a vertical scrollbar around, even if the viewport extent area is tall enough to display the entire component

VERTICAL_SCROLLBAR_AS_NEEDED

int

Shows a vertical scrollbar whenever the extent area is smaller than the full component

VERTICAL_SCROLLBAR_NEVER

int

Never shows a vertical scrollbar, even if the component is taller than the viewport extent area

HORIZONTAL_SCROLLBAR_POLICY

String

The name of the horizontal scrollbar policy property for use with property change events

VERTICAL_SCROLLBAR_POLICY

String

The name of the vertical scrollbar policy property for use with property change events

11.2.6.1 Properties

This layout manager treats the various components as properties, with the usual property access methods. However, since ScrollPaneLayout is really just a layout manager, you don't set the components, you add them to the JScrollPane. Table 11-6 shows the components managed by a ScrollPaneLayout.

Table 11-6. ScrollPaneLayout properties

Property

Data type

get

is

set

Default value

columnHeader

JViewport

·

   

null

corner

Component

·

   

null

horizontalScrollBar

JScrollBar

·

   

null

rowHeader

JViewport

·

   

null

verticalScrollbar

JScrollBar

·

   

null

viewport

JViewport

·

   

null

The columnHeader , rowHeader, and viewport components are all of type JViewport. (We will look at that class in the next section, but basically, it provides easy access for placing a viewable rectangle over a component.) If the entire component fits in the rectangle, you can see all of the component. If not, the parts outside the rectangle are cropped. The corner property is indexed using constant values from Table 11-4.

As with other layout managers, you rarely add or remove components directly through the manager; that task is handled by the container. As you saw earlier, the JScrollPane class contains the methods necessary to add or replace any of these nine components. It also contains methods to retrieve these components, but the retrieval methods are provided through the layout manager, too, for convenience.

public Rectangle getViewportBorderBounds( JScrollPane sp)

Return the bounding rectangle for sp's viewport border.

public void syncWithScrollPane( JScrollPane sp)

This method can be used with your own customized scrollpane layout manager to synchronize the components associated with the scrollpane sp and this manager. That way, any components already added to sp are appropriately recognized by your layout manager.

11.2.7 JViewport

You use the JViewport class to create a view of a potentially large component in a potentially small place. We say "potentially" because the view can encompass the entire component or just a piece of it. In the JScrollPane class, a viewport is used to show a piece of the main component, and the scrollbars provide the user with control over which piece they see. JViewport accomplishes this using the normal clipping techniques, but it guarantees that an appropriately sized view of the component is displayed. The JScrollPane class also uses JViewport objects for the row and column headers.

Most of the time, you'll leave JViewport alone and use one of the other panes, like JScrollPane, to display your components. However, nothing prevents you from using JViewport objects, and you can certainly subclass this to create some interesting tools, such as an image magnifier pane. In such a pane, you'd still have to write the magnifying code JViewport would just make it easy to see pieces of a magnified image. (The discussion of the new SpringLayout manager later in this chapter does show an example of using a JViewport on its own.)

11.2.7.1 Properties

The JViewport class has the properties shown in Table 11-7. The useful properties of JViewport deal with the view component. The view property lets you get or set the component this viewport is viewing. viewSize and viewPosition control the size and position of the area that's displayed. viewSize is normally equal to the size of the viewport, unless the component is smaller than the viewport. In that case, viewSize equals the component's size, and all of it is displayed. viewPosition is relative to the top-left corner of the component being displayed. If the backingStoreEnabled property is true, this JViewport object double-buffers the display of its contents. The isOptimizedDraw-ingEnabled( ) call always returns false to force the viewport's paint( ) method to be called, rather than allowing repaint calls to notify the viewport's children individually.

Table 11-7. JViewport properties

Property

Data type

get

is

set

Default value

accessibleContext

AccessibleContext

·

   

JViewport.AccessibleJViewport( )

backingStoreEnabled

boolean

 

·

·

false

changeListeners1.4

ChangeListener[]

·

   

Empty array

extentSize

Dimension

·

 

·

Size of the component

insets*

Insets

·

   

Insets(0, 0, 0, 0)

optimizedDrawingEnabledo

boolean

 

·

 

false

scrollMode1.3

int

·

 

·

BLIT_SCROLL_MODE

view

Component

·

 

·

null

viewPosition

Point

·

 

·

Point(0, 0)

viewRect

Rectangle

·

   

Rect(getViewPosition( ), getExtentSize( ))

viewSize

Dimension

·

 

·

Dimension(0, 0)

1.3since 1.3, 1.4since 1.4, ooverridden

*These get methods override JComponent and are final.

See also Section 11.2.8 later in the chapter and properties of the JComponent class (Table 3-6).

The scrollMode property can also affect repaint performance. The constants for valid scrolling modes are shown in Table 11-8.

Table 11-8. JViewport scrolling-mode constants

JViewport constant

Type

Effect on Scrollbar component

BLIT_SCROLL_MODE1.3

int

The default scrolling mode; the fastest for most applications.

BACKINGSTORE_SCROLL_MODE1.3

int

Uses an off-screen graphics context to do its scrolling. As the Javadoc notes, this can be advantageous, but requires a good deal more RAM.

SIMPLE_SCROLL_MODE1.3

int

Swing 1.0 and 1.1 scrolling behavior. You will almost always want one of the other modes.

1.3since 1.3

11.2.7.2 Events

The JViewport class fires a ChangeEvent whenever the view size, view position, or extent size changes.

public void addChangeListener(ChangeListener l)
public void removeChangeListener(ChangeListener l)

Add or remove a change listener for the viewport's ChangeEvents.

11.2.7.3 Constructor
public JViewport( )

Create an empty JViewport object. You can put something in the viewport using the setView( ) method.

11.2.7.4 Useful methods
public void repaint(long delay, int x, int y, int width, int height)

Override the usual repaint( ) call to make sure that only one repaint( ) is performed. This method translates the repaint rectangle to the parent's coordinate system and tells the parent to repaint( ). Presumably, if the rectangle doesn't need to be repainted, nothing happens, although the parent could have its own overridden repaint( ) method.

public void scrollRectToVisible(Rectangle rect)

Try to make the area represented by rect visible in the viewport.

public void setBounds(int x, int y, int width, int height)

Override the resize method in JComponent to make sure the backing store for this image is correct if the width or height changes from the current dimensions.

public Dimension toViewCoordinates(Dimension size)
public Point toViewCoordinates(Point p)

Translate the incoming Dimension or Point objects into corresponding objects relative to the current view. If your viewport supported logical coordinates, these methods would need to be overridden.

11.2.8 The ViewportLayout Class

As with the ScrollPaneLayout class, this class is meant to be used with a JViewport object, not for general use. That is to say, rather than attach this layout manager to your container, you should simply use a JViewport for your container. (Recall that you can place any component such as a JPanel within the viewport area.)

ViewportLayout is a straightforward implementation of the AWT LayoutManager interface and keeps the view in a useful position during resizing.



Java Swing
Graphic Java 2: Mastering the Jfc, By Geary, 3Rd Edition, Volume 2: Swing
ISBN: 0130796670
EAN: 2147483647
Year: 2001
Pages: 289
Authors: David Geary

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net