ColonelChip
ColonelChip

Reputation: 28

JPanel fills entire JScrollPane

I'm making a level editor for a project of mine so I added a JPanel to a JScrollPane in order to view the level being worked on. The idea was that if the level was too big the scroll pane would handle that. The issue is when the level is to small, when I try to size the panel to a size smaller than the scrollpane it gets stretched to fill the whole scrollpane instead of the size I set. I can't seem to find a solution to the problem.

EDIT: I added a some sample code, When the window is enlarged the panel stretches to fit the scrollpane instead of staying at the set 500 by 500 in the example.

Setting up the JScrollPane:

public class Example {

public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(600, 600);

        LevelView levelView = new LevelView();
        JScrollPane pane = new JScrollPane(levelView);

        frame.add(pane, BorderLayout.CENTER);
        frame.setVisible(true);
    }

}

JPanel:

public class LevelView extends JPanel {

    private static final long serialVersionUID = 1L;

    public LevelView() {
        Dimension dim = new Dimension(500, 500);
        setPreferredSize(dim);
        setMaximumSize(dim);
        setMinimumSize(dim);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println(getWidth() + " " + getHeight());
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, getWidth(), getHeight());


        // Draw grid
        g.setColor(Color.WHITE);
        for (int x = 0; x < getWidth(); x += 50) {
            g.drawLine(x, 0, x, getHeight());
        }
        for (int y = 0; y < getHeight(); y += 50) {
            g.drawLine(0, y, getWidth(), y);
        }

    }

}

Thanks in advance!

Upvotes: 1

Views: 1951

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347194

First of all, remember, the preferredSize of the component is providing both the size of the viewport AND the size hints for the JScrollPane

Now, before you run screaming from the room, Swing provides the Scrollable interface to allow you to provide more information to the JScrollPane and JViewport, including the preferred view port size (which allows the JScrollPane to be smaller than the preferred size of the view been displayed when it's been laid out) and, which is what you're interested in, how the view should be sized when it is smaller than the view area

ScrollMe

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.Scrollable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                TestPane tp = new TestPane();
                JSlider slider = new JSlider(50, 1024);
                slider.setValue(200);
                slider.addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        int value = slider.getValue();
                        tp.apply(new Dimension(value, value));
                        tp.revalidate();
                    }
                });

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(slider, BorderLayout.NORTH);
                frame.add(new JScrollPane(tp));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel implements Scrollable {

        private Dimension preferredSize = new Dimension(200, 200);

        public TestPane() {
            setBackground(Color.RED);
        }

        @Override
        public Dimension getPreferredSize() {
            return preferredSize;
        }

        public void apply(Dimension size) {
            preferredSize = size;
            revalidate();
        }

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

        @Override
        public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 128;
        }

        @Override
        public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 128;
        }

        @Override
        public boolean getScrollableTracksViewportWidth() {
            return false;
        }

        @Override
        public boolean getScrollableTracksViewportHeight() {
            return false;
        }

    }

}

Upvotes: 2

Tripp Kinetics
Tripp Kinetics

Reputation: 5439

Try drawing whatever it is you're drawing to a different object and add that object to a JPanel with a layout manager. Check out:

http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html

for more information about layout managers.

Upvotes: 1

Related Questions