Search code examples
javaswingjscrollpane

Swing: creating a JScrollPane that displays its component centered?


If you create a JScrollPane that has a viewport larger than the JScrollPane's component, it displays that component in the upper left.

Is there any way to change this behavior so it displays the component centered?

example program below.


clarification:

I have a component which has (width, height) = (cw,ch).

I have a JScrollPane with a viewport which has (width, height) = (vw, vh).

The component may become larger or smaller. I would like a way to use the scrollbars to position the component's centerpoint relative to the viewport's center point, so if the one or both of the component's dimensions are smaller than the viewport, the component shows up in the center of the viewport.

The default scrollpane behavior positions the component's upper left corner relative to the viewport's upper left corner.

All I'm asking is how to change the reference point. I am not sure how easy this is to do with the default JScrollPane, so if it's not easy, then I'll learn what I can and think of a different approach.


package com.example.test.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class SimpleScroller extends JFrame {
    static class Thingy extends JPanel
    {
        private double size = 20.0;

        @Override public Dimension getPreferredSize() {
            int isize = (int) this.size;
            return new Dimension(isize, isize);
        }
        @Override protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            int[] x = {0, 100, 100, 0, 0, 75, 75, 25, 25, 50};
            int[] y = {0, 0, 100, 100, 25, 25, 75, 75, 50, 50};

            Graphics2D g2d = (Graphics2D) g;
            AffineTransform at0 = g2d.getTransform();
            g2d.scale(size/100, size/100);
            g.drawPolyline(x, y, x.length);
            g2d.setTransform(at0);
        }
        public void setThingySize(double size) { 
            this.size = size;
            revalidate();
            repaint();
        }
        public double getThingySize() { return this.size; }
    }

    public SimpleScroller(String title) { 
        super(title);
        final Thingy thingy = new Thingy();
        setLayout(new BorderLayout());      
        add(new JScrollPane(thingy), BorderLayout.CENTER);

        final SpinnerNumberModel spmodel = 
            new SpinnerNumberModel(thingy.getThingySize(),
                10.0, 2000.0, 10.0);
        spmodel.addChangeListener(new ChangeListener() {
            @Override public void stateChanged(ChangeEvent e) {
                thingy.setThingySize((Double) spmodel.getNumber());
            }           
        });
        add(new JSpinner(spmodel), BorderLayout.NORTH);
    }
    public static void main(String[] args) {
        new SimpleScroller("simple scroller").start();
    }
    private void start() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
}

Solution

    1. Put a JPanel into the scroll-pane
    2. Set the layout of the panel to a GridBagLayout.
    3. Put one component into the panel with no constraint. It will be centered.

    This is the technique used in the Nested Layout Example, which places the red/orange image into the center of the parent.