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!

Synchronize two JScrollPanes

843806May 21 2009 — edited May 22 2009
Hi,

if have been trying to synchronize two JScrollPane (or rather their viewports) in terms of view position and view size. This should result in synchronized scrollbars as well. View position is simple, but I can't seem to synchronize the view size.

The only thing that worked to some degree was setting the preferredSize of the view component. But by setting the preferredSize the component will not fire any resize events anymore, which is a big problem if the view components size should not be fixed (e.g. resize when setting list data).

ViewPort.setViewSize() doesn't work either, and messes up scrolling somehow.


Here is what i got so far:
import java.awt.*;
import java.awt.event.*;
import java.util.*;

import javax.swing.*;
import javax.swing.event.*;


public class DoubleScrollPane extends JPanel {
	
	public JScrollPane sp1;
	public JScrollPane sp2;
	
	
	public DoubleScrollPane() {
		setLayout(new BorderLayout());
		
		sp1 = new JScrollPane(new JList());
		sp2 = new JScrollPane(new JList());
		
		add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sp1, sp2), "Center");
		
		ChangeListener positionListener = new ChangeListener() {
			
			@Override
			public void stateChanged(ChangeEvent e) {
				JViewport source = (JViewport) e.getSource();
				setViewPosition(source.getViewPosition());
			}
		};
		
		sp1.getViewport().addChangeListener(positionListener);
		sp2.getViewport().addChangeListener(positionListener);
		
		ComponentListener sizeListener = new ComponentAdapter() {
			@Override
			public void componentResized(ComponentEvent e) {
				Dimension union = new Dimension();
				
				for (JScrollPane sp : Arrays.asList(sp1, sp2)) {
					Dimension d = sp.getViewport().getView().getPreferredSize();
					
					union.height = Math.max(union.height, d.height);
					union.width = Math.max(union.width, d.width);
				}
				
				if (union.height * union.width > 0) {
					setViewSize(union);
				}
			}
		};
		
		sp1.getViewport().getView().addComponentListener(sizeListener);
		sp2.getViewport().getView().addComponentListener(sizeListener);
	}
	

	public void setViewPosition(Point pos) {
		for (JScrollPane sp : Arrays.asList(sp1, sp2)) {
			sp.getViewport().setViewPosition(pos);
		}
		
		repaint();
	}
	

	public void setViewSize(Dimension size) {
		for (JScrollPane sp : Arrays.asList(sp1, sp2)) {
			// this works exactly once, but then the list size is fixed
			// sp.getViewport().getView().setPreferredSize(size);
			
			// this doesn't work and messes up scrolling somehow
			// sp.getViewport().setViewSize(size);
		}
		
		revalidate();
		repaint();
	}
	

	public static void main(String[] args) throws Exception {
		SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				JFrame frame = new JFrame();
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				
				final DoubleScrollPane dsp = new DoubleScrollPane();
				
				frame.getContentPane().add(dsp, "Center");
				frame.getContentPane().add(new JButton(new AbstractAction("Insert") {
					
					@Override
					public void actionPerformed(ActionEvent e) {
						// big list
						((JList) dsp.sp1.getViewport().getView()).setModel(new AbstractListModel() {
							
							final int size = new Random().nextInt(200) + 50;
							
							
							@Override
							public int getSize() {
								return size;
							}
							

							@Override
							public Object getElementAt(int index) {
								return String.format("%0" + (index + 1) + "d", index);
							}
						});
						
						// small list
						((JList) dsp.sp2.getViewport().getView()).setModel(new AbstractListModel() {
							
							final int size = new Random().nextInt(20) + 5;
							
							
							@Override
							public int getSize() {
								return size;
							}
							

							@Override
							public Object getElementAt(int index) {
								return index;
							}
						});
					}
				}), "South");
				
				frame.setSize(550, 500);
				frame.setVisible(true);
			}
		});
		
	}
}
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Jun 19 2009
Added on May 21 2009
5 comments
892 views