5

It is said in manual, that if child does not implement Scrollable, then JScrollPane rely on preferredSize properties of it's content.

Apparently this is not true for me. I am increasing preferred height, but JScrollPane does not feel or react on it.

package tests;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Try01_JScrollPane extends JFrame {

    private static final long serialVersionUID = 4123186105171813186L;

    private static final Logger log = LoggerFactory.getLogger(Try01_JScrollPane.class);

    JPanel yellowPanel = new JPanel();
    {
        yellowPanel.setPreferredSize(new Dimension(200,50));
        yellowPanel.setSize(new Dimension(200,50));
        yellowPanel.setBackground(Color.yellow);
    }

    JScrollPane scrollPane = new JScrollPane(yellowPanel);
    {
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    }

    AbstractAction increaseAction = new AbstractAction() {

        @Override
        public void actionPerformed(ActionEvent e) {
            yellowPanel.setPreferredSize(new Dimension(yellowPanel.getPreferredSize().width, yellowPanel.getPreferredSize().height+100));
            log.debug("preferred height is now {}", yellowPanel.getPreferredSize().height);
        }
    };

    Timer increaseTimer = new Timer(1000, increaseAction);

    {
        setLayout(new BorderLayout());
        add(scrollPane, BorderLayout.CENTER);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(200, 400);

        setTitle("Try01_JScrollPane");

        increaseTimer.start();
        setVisible(true);
    }

    public static void main(String[] args) {

        new Try01_JScrollPane();

    }


}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
Dims
  • 47,675
  • 117
  • 331
  • 600
  • 1
    Did you forget to `pack()`? [Don't use `setPreferredSize()` when you really mean to override `getPreferredSize()`](http://stackoverflow.com/q/7229226/230513). See also [*Initial Threads*](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html). – trashgod Jun 13 '14 at 11:07
  • Please factor out `org.slf4j` and make it an [MCVE](http://stackoverflow.com/help/mcve). – Andrew Thompson Jun 13 '14 at 11:12
  • and there is another issue - JScrollPane, JComboBox and JTable cant returns reasonable (their own) PreferredSize, – mKorbel Jun 13 '14 at 11:14
  • I'd also ask why you're using both `setPreferredSize()` and `setSize()`. – Gorbles Jun 13 '14 at 11:14

2 Answers2

2

The JScrollPane cuts a view port out of a backing content have a scroll pane layout. The part on getPreferredSize refers to this layout. It simply says that the JScrollPane / view port rectangle is not influenced by the backing content and vice versa: content is layed out with respect to their preferred size.

So a change of preferred size need a new layouting. More sence would be to:

  • initialize with a setPreferredSize.
  • afterwards call setSize to resize.
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
2

JPanel is container and JComponent too, for any changes to JViewport you have to notify the JScrollPane:-)

enter image description here

.

enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Try01_JScrollPane extends JFrame {

    private static final long serialVersionUID = 4123186105171813186L;
    private JFrame frame = new JFrame("Try01_JScrollPane");
    private JPanel yellowPanel = new JPanel();

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(300, 200);
    }

    {
        yellowPanel.setBackground(Color.yellow);
    }
    private JScrollPane scrollPane = new JScrollPane(yellowPanel);

    {
        scrollPane.setPreferredSize(new Dimension(400, 300));
    }
    private AbstractAction increaseAction = new AbstractAction() {
        private static final long serialVersionUID = 1L;

        @Override
        public void actionPerformed(ActionEvent e) {
            yellowPanel.setPreferredSize(
                    new Dimension(yellowPanel.getPreferredSize().width + 100,
                    yellowPanel.getPreferredSize().height + 100));
            yellowPanel.revalidate();
            yellowPanel.repaint();
        }
    };
    private Timer increaseTimer = new Timer(1000, increaseAction);

    public Try01_JScrollPane() {
        frame.add(scrollPane, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocation(150, 150);
        frame.setVisible(true);
        increaseTimer.start();
        increaseTimer.setRepeats(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Try01_JScrollPane();
            }
        });
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • You should not be setting the preferred size out side of your class. Application code should not have to remember to use revalidate() and repaint(). Swing components are designed to valadite and repaint themselves whenever a property of the class is changed. Instead you should be creating an `increase(...)` method for your class. You would also override the `getPreferredSize()` method to calculate the preferred size of the component based on some internal property. Then the `increase()` method would update that internal property and invoke revalidate() and repaint(). method would update a – camickr Jun 13 '14 at 15:39
  • @camickr agree, but the empty JPanel in JScrollPane has described issue, because it doesn't contains any childs – mKorbel Jun 13 '14 at 17:49