Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Programmatically Scroll JScrollPane - Best Practice

800581Mar 20 2010 — edited Mar 20 2010
Having a bit of trouble finding the best (most foolproof/efficient/correct) way of programmatically scrolling a JScrollPane to make sure a component is visible. I've written a little demo for the solution I have at the moment and was wondering if it can be improved upon.

The demo creates 100 clickable JLabels in the right section of the JSplitPane and 100 JLabels with the corresponding integer value in the left section. When the user clicks on a JLabel in the right section the JLabel with the corresponding value in the left section is highlighted red in foreground colour and if the label isn't currently visible the scroll pane is scrolled to show it. This appears to be working OK, but I don't know if it's the best it could be. As you can see from the section that's commented out I've tried to use the scrollRectToVisible method of the viewport in the scroll pane but it's not consistently making the correct label visible.

Thanks in advance for any advice.
package tester;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;

public class AutoscrollingExample extends JFrame {
	private final int TOTAL_LABELS = 100;
	
	// Keeps track of label for int value in left box
	private Map<Integer, JLabel> labelsInLeftBoxMap = new HashMap<Integer, JLabel>();
	
	private JScrollPane leftScrollPane;
	
	public static void main(String[] args) {
		new AutoscrollingExample();
	}
	
	private AutoscrollingExample() {
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		splitPane.setLeftComponent(getLeftScrollPane());
		splitPane.setRightComponent(getRightBox());
		
		splitPane.setDividerLocation(splitPane.getLeftComponent().getPreferredSize().width + 25);
		
		this.setLayout(new BorderLayout());
		this.add(splitPane, BorderLayout.CENTER);
		this.setLocationByPlatform(true);
		this.setSize(400, 400);
		this.setResizable(false);
		this.setTitle("Scroll Testing");
		this.setVisible(true);
	}
	
	private Box getRightBox() {
		Box rightBox = Box.createVerticalBox();
		
		int boxEveryXNumbers = 10;
		Box currentBox = new Box(BoxLayout.LINE_AXIS);
		
		for(int i=1; i<=TOTAL_LABELS; i++) {
			JLabel thisLabel;
			if(i < 10) {
				thisLabel = new JLabel("  "+i+" ");
			} else {
				thisLabel = new JLabel(" "+i+" ");
			}
			
			thisLabel.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					handleMouseClickOnLabel(e);
				}
			});
			
			currentBox.add(thisLabel);
			currentBox.add(Box.createHorizontalStrut(5));
			
			if(i > 0 && i % boxEveryXNumbers == 0) {
				rightBox.add(currentBox);
				rightBox.add(Box.createVerticalStrut(5));
				
				currentBox = new Box(BoxLayout.LINE_AXIS);
			}
		}
		
		rightBox.add(Box.createVerticalGlue());
		
		return rightBox;
	}
	
	private JScrollPane getLeftScrollPane() {
		Box leftBox = Box.createVerticalBox();
		
		for(int i=1; i<=TOTAL_LABELS; i++) {
			JLabel leftLabel = new JLabel(" "+i+" ");
			
			labelsInLeftBoxMap.put(i, leftLabel);
			
			leftBox.add(leftLabel);
		}
		
		leftScrollPane = new JScrollPane();
		leftScrollPane.getViewport().add(leftBox);
		
		return leftScrollPane;
	}
	
	private void handleMouseClickOnLabel(MouseEvent e) {
		// Get the int value of clicked label by parsing trimmed text
		JLabel sourceLabelInRightBox = (JLabel) e.getSource();
		int clickedLabelNumber = Integer.parseInt(sourceLabelInRightBox.getText().trim());
		
		System.out.println("clickedLabelNumber: "+clickedLabelNumber);

		// Highlight the selected label and reset highlight on other labels
		for(Integer oneKey : labelsInLeftBoxMap.keySet()) {
			if(oneKey.equals(clickedLabelNumber)) {
				labelsInLeftBoxMap.get(oneKey).setForeground(Color.red);
			} else {
				labelsInLeftBoxMap.get(oneKey).setForeground(Color.black);
			}
		}

		/*
		 * Attempt to scroll the left scroll pane to ensure the selected label
		 * is visible
		 */
		JLabel labelInLeftComponent = labelsInLeftBoxMap.get(clickedLabelNumber);
		
		Rectangle leftLabelRectangle = new Rectangle(
				labelInLeftComponent.getLocation().x, 
				labelInLeftComponent.getLocation().y, 
				labelInLeftComponent.getSize().width, 
				labelInLeftComponent.getSize().height);
		
		System.out.println(labelInLeftComponent.getLocation());
		
		if(!SwingUtilities.isRectangleContainingRectangle(leftScrollPane.getViewport().getViewRect(), 
				leftLabelRectangle)) {
			System.out.println("label isn't visible - attempting to scroll");
			
			leftScrollPane.getViewport().setViewPosition(leftLabelRectangle.getLocation());
			
			// scrollRectToVisible doesn't consistently scroll so label is visible
			// leftScrollPane.getViewport().scrollRectToVisible(leftLabelRectangle);
		} else {
			System.out.println("label is already visible - doing nothing");
		}
	}
}
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Apr 17 2010
Added on Mar 20 2010
2 comments
1,675 views