Salem
Salem

Reputation: 14907

Fix height of JScrollPane

I had no idea if the problem I'm facing was specific to my situation only, so I wrote a stripped-down version of what's causing my problem (with JLabels as a sample component).

public class InterestingBehavior {

    static int direction = -4;
    static final boolean useScroll = true;
    static final String longString = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                                             + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

    public static void main(String[] args) {
        JFrame test = new JFrame("Test");
        test.setSize(500, 300);
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        test.setLayout(new BoxLayout(test.getContentPane(), BoxLayout.Y_AXIS));
        for (int i = 0; i < 10; i++)
            test.add(useScroll ? new JScrollPane(new JLabel(longString)) : new JLabel(longString));
        test.add(Box.createVerticalGlue()); //should use all available space

        final int min = 300, max = 600;
        new Timer(50, e -> {
            int h = test.getHeight();
            SwingUtilities.invokeLater(() -> test.setSize(test.getWidth(), h + direction));
            direction = h == min || h == max ? -direction : direction;
        }).start();

        test.setVisible(true);
    }

}

The frame resizes itself to show what I want/don't want. Adding JLabels to the BoxLayout keeps them all at the top of the JFrame - this is what I want, because I added vertical glue to the panel. However if I wrap the JLabel in a JScrollPane, it decides to automatically resize itself vertically based on the height of the JFrame - how can I avoid this behavior and keep the scroll pane at a constant height?

The frame:

expanded scroll pane

when resized, becomes

small pane

which is not what I want.

How can I keep one dimension fixed to exactly that of the child component (viewport)?

Upvotes: 4

Views: 8464

Answers (1)

Alexander
Alexander

Reputation: 1421

The problem is that JScrollPane itself grabs all space it gets. The BoxLayout fairly distributes the available space between the JScrollPanes and the vertical glue.

The solution is to limit the vertical space the JScrollPanel demands using e.g. jScrollPane.setMaxmimumSize(new Dimension(1000, 50)).

Now, you have each ScrollPane grabbing exactly this space which leads to weird behaviour when resizing and actually needing the horizontal scrollbar painted. Therefore you may want to have a preferred size e.g. jScrollPane.setPreferredSize(new Dimension(0, 50)), too.

Here the complete example:

    static int direction = -4;
    static final boolean useScroll = true;
    static final String longString = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                                             + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

    public static void main(String[] args) {
        JFrame test = new JFrame("Test");
        test.setSize(500, 300);
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        test.setLayout(new BoxLayout(test.getContentPane(), BoxLayout.Y_AXIS));
        for (int i = 0; i < 10; i++) {
            if(useScroll) {
                JScrollPane jScrollPane = new JScrollPane(new JLabel(longString));
                jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                jScrollPane.setMaximumSize(new Dimension(1000, 50));
                jScrollPane.setPreferredSize(new Dimension(0, 50));
                test.add(jScrollPane);
            } else {
                 test.add(new JLabel(longString));
            }
        }
        test.add(Box.createVerticalGlue()); //should use all available space

        final int min = 300, max = 600;
        new Timer(50, e -> {
            int h = test.getHeight();
            SwingUtilities.invokeLater(() -> test.setSize(test.getWidth(), h + direction));
            direction = h == min || h == max ? -direction : direction;
        }).start();

        test.setVisible(true);
    }

Upvotes: 6

Related Questions