Swing - JScollArea в GridBagLayout сворачивается при изменении размера - PullRequest
0 голосов
/ 26 мая 2020

Я пишу приложение для просмотра изображений с центральной областью, содержащей изображение, плюс панели инструментов и т. Д. c. вокруг него.

Я выбрал GridBagLayout для необходимой мне гибкости, но как только главное окно уменьшается, вместо появления полос прокрутки вокруг изображения вся область прокрутки сворачивается до области 0x0px.

Ниже приведен минимальный код, иллюстрирующий это. Попробуйте оставить размеры 500x500 и уменьшить окно на несколько пикселей, перетащив один из его углов внутрь:

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

public class ScrollTest3 {

    private static final int IMG_WIDTH = 500; // 50 or 500 or 2000
    private static final int IMG_HEIGHT = 500; // 50 or 500 or 2000

    private static GridBagConstraints getScrollPaneConstraints() {
        GridBagConstraints c = new GridBagConstraints();
        c.gridx = 0;
        c.gridy = 1;
        c.weightx = 1;
        c.weighty = 1;

        // With the next line, shrinking the window makes scrollbars appear ok,
        // ... but making it larger causes the scrollpane to stick at the top left
        // Without the next line, enlarging the window keeps image centered,
        // ... but making it smaller causes the scrollpane to collapse

        //c.fill = GridBagConstraints.BOTH;

        return c;
    }

    public static void addComponentsToPane(Container container) {
        container.setLayout(new GridBagLayout());

        // Add top bar
        container.add(new JLabel("This would be a top bar with information"), new GridBagConstraints());

        // Prepare main image panel
        JPanel imagePanel = new JPanel() {
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                // Image replaced by a shape for demonstration purpose
                g2d.drawOval(0, 0, IMG_WIDTH, IMG_HEIGHT);
            }

            public Dimension getMinimumSize() {
                return new Dimension(IMG_WIDTH, IMG_HEIGHT);
            }

            public Dimension getPreferredSize() {
                return new Dimension(IMG_WIDTH, IMG_HEIGHT);
            }

            public Dimension getMaximumSize() {
                return new Dimension(IMG_WIDTH, IMG_HEIGHT);
            }
        };
        JScrollPane scrollableImagePanel = new JScrollPane(imagePanel);

        container.add(scrollableImagePanel, getScrollPaneConstraints());
    }

    private static void limitAppSize(JFrame frame) {
        frame.pack();

        Dimension preferred = frame.getSize();
        GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
        Rectangle bounds = env.getMaximumWindowBounds();

        preferred.width = Math.min(preferred.width, bounds.width);
        preferred.height = Math.min(preferred.height, bounds.height);

        frame.setSize(preferred);
    }


    private static void createAndShowGUI() {
        JFrame frame = new JFrame("ScrollTest3");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        addComponentsToPane(frame.getContentPane());
        limitAppSize(frame);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGUI());
    }
}

Как вы можете видеть в закомментированной строке, это можно «исправить», указав GridBagConstraints .BOTH для поля "заполнить", но тогда изображения меньшего размера (попробуйте с 50x50) больше не центрируются: - (

Есть ли способ указать это:

  • если изображение меньше, чем область отображения, оно должно быть центрировано
  • если изображение больше, чем область отображения, область прокрутки должна заполнять всю область отображения

?

1 Ответ

1 голос
/ 26 мая 2020

... но увеличение его размера приводит к тому, что полоса прокрутки остается в верхнем левом углу

Ограничения weightx / y указывают GridBayLayout, как выделить дополнительное пространство в кадре. Поскольку у вас есть только один компонент с ненулевыми значениями, все дополнительное пространство уходит на панель. Таким образом, компонент располагается вверху / слева от места, доступного под меткой.

g2d.drawOval(0, 0, IMG_WIDTH, IMG_HEIGHT);

Тогда ваш код рисования всегда закрашивает овал вверху / слева относительно расположения панелей.

Если вы хотите, чтобы овал был центрирован, тогда ваш код рисования должен измениться:

//g2d.drawOval(0, 0, IMG_WIDTH, IMG_HEIGHT);
int x = (getWidth() - IMG_WIDTH) / 2;
int y = (getHeight() - IMG_HEIGHT) / 2;
g2d.drawOval(x, y, IMG_WIDTH, IMG_HEIGHT);

Я пишу приложение для просмотра изображений с центральной областью, содержащей изображение

Однако, как было предложено в комментариях к вашему последнему вопросу, самое простое решение - просто использовать JLabel для отображения изображения. JLabel автоматически центрирует изображение в пространстве, доступном для метки.

Обратите внимание, что именно поэтому текст вашей метки центрируется по горизонтали при изменении ширины рамки.

...