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);
}
});
}
}