Swing - JScollArea in GridBagLayout collapses when resizing

时光毁灭记忆、已成空白 提交于 2020-06-17 10:25:32

问题


I'm writing an "image viewer" app with a central area containing the image, plus toolbars etc. around it.

I selected a GridBagLayout for the flexibility I need, but as soon as the main window is reduced, instead of having scrollbars appearing around the image, the whole scrollpane collapses to a 0x0px area.

Please find below a minimal code to illustrate this. Try leaving the dimensions at 500x500 and reducing the window by a few pixels by dragging one of its corners inwards:

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

As you can see in the commented out line, it can be "fixed" by specifying GridBagConstraints.BOTH for the "fill" field, but then smaller images (try with 50x50) are not centered anymore :-(

Is there a way to specify that:

  • if the image is smaller than the display area, it should be centered
  • if the image is larger than the display area, the scroll pane should fill the full display area

?


回答1:


... but making it larger causes the scrollpane to stick at the top left

The weightx/y constraints tells the GridBayLayout how to allocate extra space in the frame. Since you only have a single component with non-zero values all the extra space goes to the panel. So the component is positioned at the top/left of the space available under the label.

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

Then your painting code always paints the oval at the top/left relative to the panels location.

If you want the oval centered, then your painting code must change:

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

I'm writing an "image viewer" app with a central area containing the image

However, as was suggested in the comments of your last question, the easiest solution is to just use a JLabel to display the image. The JLabel will automatically center the image in the space available to the label.

Note, this is also why your label text is centered horizontally as you change the width of the frame.



来源:https://stackoverflow.com/questions/62021983/swing-jscollarea-in-gridbaglayout-collapses-when-resizing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!