Dims
Dims

Reputation: 51259

How to implement JScrollPane child behavior?

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();

    }


}

Upvotes: 5

Views: 432

Answers (2)

mKorbel
mKorbel

Reputation: 109823

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();
            }
        });
    }
}

Upvotes: 2

Joop Eggen
Joop Eggen

Reputation: 109613

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.

Upvotes: 2

Related Questions