且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

JPanel填充整个JScrollPane

更新时间:2023-12-05 20:22:28

首先,请记住,组件的preferredSize同时提供了视口的大小和JScrollPane

的大小提示>

现在,在从房间尖叫之前,Swing提供了Scrollable界面,可让您向JScrollPaneJViewport提供更多信息,包括首选的视口尺寸(允许使用JScrollPane小于视图在布局时显示的首选大小),这就是您感兴趣的,当视图小于视图区域时应如何调整视图大小

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

    }

}

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!

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

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

    }

}