import java.awt.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; /** * Simple panel that illustrates the synchronization of two JScrollPanes. * The number of elements in the two JList components do not have to be * the same. The ChangeListener will synchronize their respective * BoundedRangeModels and scale as necessary. *

Note: Since it is the right JScrollBar's model-ChangeListener * that listens for changes from the left JScrollBar, it is the right JList * that controls the total number of elements shown in the JScrollPanes.

* * * @author R. Kevin Cole */ public class ScrollBarSynchronizer extends JPanel { /** Two JLists are created and initialized from Vectors and * then added to JScrollPanes to test the synchronized JScrollBars. */ public ScrollBarSynchronizer() { super(new BorderLayout()); // create something to scroll Vector leftData = new Vector(); Vector rightData = new Vector(); for (int i = 0; i < 71; i++) { rightData.add("Right " + i); // the modulo operator is used to create a different number // of elements within each scrolling region. if ((i % 2) == 0) { leftData.add("Left " + i); } } JScrollPane leftScroller = new JScrollPane(new JList(leftData)); leftScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); JScrollPane rightScroller = new JScrollPane(new JList(rightData)); JScrollBar leftBar = leftScroller.getVerticalScrollBar(); JScrollBar rightBar = rightScroller.getVerticalScrollBar(); MyChangeListener listener = new MyChangeListener(leftBar.getModel()); rightBar.getModel().addChangeListener(listener); JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftScroller, rightScroller); add(split, BorderLayout.CENTER); } /** Test routine. */ public static void main(String[] arg) { JFrame frame = new JFrame("Test ScrollBarSynchronizer"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setContentPane(new ScrollBarSynchronizer()); frame.setSize(640, 480); frame.setLocation(100, 100); frame.setVisible(true); } } /** * Synchronize the data models of any two JComponents that use a * BoundedRangeModel ( such as a JScrollBar, JSlider or ProgressBar). * * @see javax.swing.BoundedRangeModel * @see javax.swing.event.ChangeListener * @Author R. Kevin Cole */ class MyChangeListener implements ChangeListener { private BoundedRangeModel myModel; /** * @param model This model is forced to move in synchronization * to this ChangeListener's event-source. */ public MyChangeListener( BoundedRangeModel model ) { myModel = model; } // - begin - implementation of ChangeListener // /** * Envoked when the target of the listener has changed its state. */ public void stateChanged( ChangeEvent e ) { BoundedRangeModel sourceModel = (BoundedRangeModel) e.getSource(); int sourceDiff = sourceModel.getMaximum() - sourceModel.getMinimum(); int destDiff = myModel.getMaximum() - myModel.getMinimum(); int destValue = sourceModel.getValue(); if( sourceDiff != destDiff ) destValue = (destDiff * sourceModel.getValue())/sourceDiff; myModel.setValue( myModel.getMinimum() + destValue ); } // // - end - implementation of ChangeListener }