Изменение размера JScrollpane с содержимым переменного размера

Мое изменяемое размерное содержимое JScrollPane имеет минимальную ширину. Если JScrollPane меньше этой ширины, должны появляться горизонтальные полосы прокрутки. Если он больше этой ширины, содержимое видового экрана должно расширяться, чтобы заполнить весь видовой экран.

Похоже на простую концепцию, и у меня есть что-то, что работает, но это похоже на взлом:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

public class SSBTest {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                final Component view = new MyView();
                final JScrollPane jScrollPane = new JScrollPane(view);
                jScrollPane.addComponentListener(new ComponentAdapter() {
                    @Override
                    public void componentResized(final ComponentEvent e) {
                        final Dimension minimumSize = view.getMinimumSize();
                        final int width = Math.max(minimumSize.width, jScrollPane.getViewport().getWidth());
                        view.setPreferredSize(new Dimension(width, minimumSize.height));
                    }
                });
                showInDialog(jScrollPane);
            }
        });
    }

    private static void showInDialog(final JScrollPane jScrollPane) {
        final JDialog dialog = new JOptionPane(jScrollPane).createDialog("JScrollPane Resize Test");
        dialog.setResizable(true);
        dialog.setModal(true);
        dialog.setVisible(true);
        System.exit(0);
    }

    private static final class MyView extends JPanel {
        @Override
        protected void paintComponent(final Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.RED);
            g.drawString("Dimensions are " + getSize(), 10, 20);
            g.drawRect(0, 0, getMinimumSize().width-1, getMinimumSize().height-1);
            g.setColor(Color.BLUE);
            g.drawRect(0, 0, getPreferredSize().width-1, getPreferredSize().height-1);
        }

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

        @Override
        public Dimension getPreferredSize() {
            return super.getPreferredSize();
        }
    }
}

Изменение размера диалогового окна запускает компонент ComponentListener, который явно устанавливает предпочтительный размер представления в окне просмотра, инициируя проверку компонентов. Однако изменение размера вызывает неустойчивые полосы прокрутки. Есть ли более чистый способ сделать это?

EDIT: благодаря camickr для ссылки ScrollablePanel, я изменил свой класс JPanel для реализации Scrollable и динамически изменил возвращаемое значение для getScrollableTracksViewportWidth().

Когда область просмотра большая, я возвращаю true для getScrollableTracksViewportWidth(), сообщая JScrollPane, чтобы заполнить представление моим компонентом. Когда область просмотра мала, я возвращаю false, поэтому появятся полосы прокрутки.

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

public class SSBTest {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                final Component view = new MyView();
                final JScrollPane jScrollPane = new JScrollPane(view);
                showInDialog(jScrollPane);
            }
        });
    }

    private static void showInDialog(final JScrollPane jScrollPane) {
        final JDialog dialog = new JOptionPane(jScrollPane).createDialog("JScrollPane Resize Test");
        dialog.setResizable(true);
        dialog.setModal(true);
        dialog.setVisible(true);
        System.exit(0);
    }

    private static final class MyView extends JPanel implements Scrollable {
        @Override
        protected void paintComponent(final Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.RED);
            g.drawString("MyView: " + getWidth() + "x" + getHeight(), 10, 20);
            g.drawRect(0, 0, getMinimumSize().width-1, getMinimumSize().height-1);
            g.setColor(Color.BLUE);
            g.drawRect(0, 0, getPreferredSize().width-1, getPreferredSize().height-1);
            g.drawString("Preferred/Minimum Size", 10, getPreferredSize().height/2);
            g.setColor(Color.GREEN);
            g.drawLine(0, 0, getWidth(), getHeight());
        }

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

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

        public Dimension getPreferredScrollableViewportSize() {
            return getPreferredSize();
        }

        public int getScrollableUnitIncrement(final Rectangle visibleRect, final int orientation, final int direction) {
            return 10;
        }

        public int getScrollableBlockIncrement(final Rectangle visibleRect, final int orientation, final int direction) {
            return visibleRect.width;
        }

        public boolean getScrollableTracksViewportWidth() {
            final Container viewport = getParent();
            return viewport.getWidth() > getMinimumSize().width;
        }

        public boolean getScrollableTracksViewportHeight() {
            return true;
        }

    }
}

Ответ 1

Не уверен, но вы можете использовать Scrollable Panel. Вы можете настроить изменение размера компонента (попробуйте использовать STRETCH). Код работает с предпочтительным размером компонента, а не с минимальным размером, поэтому может быть не совсем то, что вам нужно.