10

I have JScrollPane that contains some images in a horizontal row. If the row of images is too long for the view port, the JScrollPane shows a scroll bar, reducing the height of the view port. I'd like to resize the images to fit the view port. How can I detect that the view port changed its size? Unfortunately, registering change event handlers doesn't seem to work.

mKorbel
  • 109,525
  • 20
  • 134
  • 319
xmjx
  • 1,163
  • 1
  • 7
  • 18

2 Answers2

14

Using change listener on the ViewPort seems to work for me. Here is a small demo of that:

import java.awt.BorderLayout;
import java.io.UnsupportedEncodingException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Main {

    public static void main(String[] args) throws UnsupportedEncodingException {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel(new BorderLayout());
        final JPanel buttons = new JPanel();
        final JScrollPane pane = new JScrollPane(buttons);
        pane.getViewport().addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                System.err.println("Change in " + e.getSource());
                System.err.println("Vertical visible? " + pane.getVerticalScrollBar().isVisible());
                System.err.println("Horizontal visible? " + pane.getHorizontalScrollBar().isVisible());
            }
        });
        panel.add(pane);
        frame.setContentPane(panel);
        frame.setSize(300, 200);
        frame.setVisible(true);
        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {

            @Override
            protected Void doInBackground() throws Exception {
                for (int i = 0; i < 10; i++) {
                    Thread.sleep(800);
                    buttons.add(new JButton("Hello " + i));
                    buttons.revalidate();
                }
                return null;
            }
        };
        worker.execute();
    }
}
Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
  • Okay, weird. Thanks for the quick reply. I tried that and it works, indeed. Alas, inside of my application, adding a change listener does not work. I'll work from here. – xmjx May 02 '12 at 10:02
  • For some strange reason outputs to both stdout and stderr were not displayed in the listener. So it basically was a debugging problem. Thanks again. – xmjx May 02 '12 at 10:51
1

I used the HierarchyBoundsListener to detect changes in the JScrollPane's size:

onAncestorResized(scroll, evt -> resizeYourImages());

Here's a convenience method for attaching the listener:

static void onAncestorResized(JComponent component, Consumer<HierarchyEvent> callback) {
    component.addHierarchyBoundsListener(new HierarchyBoundsAdapter() {
        @Override
        public void ancestorResized(HierarchyEvent e) {
            callback.accept(e);
        }
    });
}
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171