6

I have been trying for hours to find a way to solve the issue, but I had no luck with that. Here is a sample code:

import java.awt.BorderLayout;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class Example extends JFrame
{
    private static final long serialVersionUID = 1L;

    public Example()
    {
        JPanel contentPane = (JPanel) getContentPane();
        contentPane.setLayout(new BorderLayout());

        JPanel panTop = new JPanel(new BorderLayout());
        //JPanel panBottom = new JPanel(new BorderLayout());

        JPanel panTopCenter = new JPanel();
        //JPanel panTopLeft = new JPanel();
        //JPanel panTopRight = new JPanel();

        panTop.add(panTopCenter, BorderLayout.CENTER);
        //panTop.add(panTopLeft, BorderLayout.WEST);
        //panTop.add(panTopRight, BorderLayout.EAST);

        contentPane.add(panTop, BorderLayout.CENTER);
        //contentPane.add(panBottom, BorderLayout.SOUTH);

        JPanel pan = new JPanel();
        pan.setLayout(new BoxLayout(pan, BoxLayout.Y_AXIS));
        for(int i = 0; i < 50; i++) pan.add(new JButton("Button " + i));
        JScrollPane scrollPane = new JScrollPane(pan);
        panTopCenter.add(scrollPane);

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {           
            @Override
            public void run()
            {
                new Example();
            }
        });
    }
}

Snapshot:

enter image description here

Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
  • Instead of using `BoxLayout`, do try `GridLayout`, as shown in this [example](http://stackoverflow.com/questions/10331129/jscrollpane-resize-containing-jpanel-when-scrollbars-appear/10333957#10333957), Since in `GridLayout` all `JButton`s will be of equal sizes, unlike `BoxLayout`, where size is determined by the text inside it. – nIcE cOw Jun 13 '12 at 13:24

4 Answers4

7

I always have to set the viewport's preferred size like this.

import java.awt.*;
import javax.swing.*;

public class Example extends JFrame {

    public Example() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        Box box = new Box(BoxLayout.Y_AXIS);
        for (int i = 0; i < 50; i++) {
            box.add(new JButton("Button " + i));
        }
        JScrollPane sp = new JScrollPane(box);
        Dimension d = new Dimension(box.getComponent(0).getPreferredSize());
        sp.getVerticalScrollBar().setUnitIncrement(d.height);
        d.height *= 10; // Show at least 10 buttons
        sp.getViewport().setPreferredSize(d);

        add(sp, BorderLayout.CENTER);
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                Example e = new Example();
            }
        });
    }
}
Catalina Island
  • 7,027
  • 2
  • 23
  • 42
7

Don't set any sizes! The scroll-bar appears if this change is made.

JPanel panTopCenter = new JPanel(new GridLayout());

The basic problem is that FlowLayout will show components at the smallest size needed to display it, and for a scroll-pane, that is (decided to be) 0x0. By using a GridLayout with no arguments in the constructor and adding the scroll-pane as the only component, it will be forced to fill the available space.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 1
    +1 IIUC, the problem is that the resulting viewport preferred size is unwieldy and (possibly) L&F dependent. I would advocate implementing `getPreferredScrollableViewportSize()`. – trashgod Jun 13 '12 at 16:53
  • @trashgod I can see situations where setting a preferred view port size might be needed, but am always very cautious about 'set **any** size'. It is something I only look to, after exhausting other likely possibilities. – Andrew Thompson Jun 13 '12 at 17:05
  • @both I admit, I do not understand very well this question +1 for maybe correct answer – mKorbel Jun 13 '12 at 18:59
  • @mKorbel *"I do not understand very well this question"* This is a question where the answer lies in details not immediately known. I would generally use elements in the rest of the GUI to form a 'reasonable size' (based on columns/rows etc.) and use those size hints for a scrollable component (or a list) in another area of the GUI for the 'we have a lot of these' type components/elements. In fact even with the list (`JList`) we can suggest a row size, so that helps as well. – Andrew Thompson Jun 13 '12 at 19:41
  • aaaachhhh I see that, sure my bad 'cos `1)` by default remove balast from questions before creating my answer `2)` returns back only to the questions about L&F, UIManager and last 2M to compare mess became from Java7 ([I think that not correct answer](http://stackoverflow.com/a/11000070/714968), but works in limited form like as example) `3)` never used FlowLayout / BoxLayout – mKorbel Jun 13 '12 at 20:57
2

You have to set the preferred-size, in the case that JScrollPane is single JComponent in the container or top-level container.

scrollPane.setPreferredSize(new Dimension(100,500));

Better would be to use GridLayout for the same type of JComponents.

Radu Murzea
  • 10,724
  • 10
  • 47
  • 69
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • But when I do that, `panTopCenter` will have a static size and won't dynamically enlarge upon enlarging the JFrame size. – Eng.Fouad Jun 13 '12 at 07:18
  • I think you can change the viewport's size like [here](http://stackoverflow.com/a/11016543/261156). – Catalina Island Jun 13 '12 at 14:03
  • Ah, similar to what `setVisibleRowCount()` does for `JList`, as shown [here](http://stackoverflow.com/a/5760093/714968). – trashgod Jun 13 '12 at 16:32
0

The best solution, quick and easy, is using JXPanel from SwingX, which is quasi-standard and implements Scrollable.