【问题标题】:Swing - JScollArea in GridBagLayout collapses when resizingSwing - 调整大小时 GridBagLayout 中的 JScollArea 折叠
【发布时间】:2020-09-13 05:55:21
【问题描述】:

我正在编写一个“图像查看器”应用程序,其中包含一个包含图像的中心区域,以及它周围的工具栏等。

我选择了一个 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)不再居中:-(

有没有办法指定:

  • 如果图像小于显示区域,则应居中
  • 如果图像大于显示区域,滚动窗格应填满整个显示区域

?

【问题讨论】:

    标签: java swing window jscrollpane gridbaglayout


    【解决方案1】:

    ...但是增大它会导致滚动窗格粘在左上角

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

    我正在编写一个“图像查看器”应用程序,其中心区域包含图像

    但是,正如您在上一个问题的 cmets 中所建议的那样,最简单的解决方案是仅使用 JLabel 来显示图像。 JLabel 将自动将图像置于标签可用空间的中心。

    请注意,这也是您更改框架宽度时标签文本水平居中的原因。

    【讨论】:

    • 感谢这个有见地的回答。我不使用 JLabel 的原因是因为我想在图像上方覆盖注释(组件)。这就是为什么我还希望内部 JPanel 是图像的确切大小,以便注释相对于 JPanel 的(0,0)(即图像的(0,0))绘制自己。我知道 weightX/Y 会导致单元格内容增长(填充 = BOTH),但是是否可以插入一个中间面板来占据整个显示区域但包含居中的 JScrollPane ?披露:尝试过,但无济于事:-(
    • 1) 你的原始问题得到了回答(你已经添加了一个不同的要求,即包含图像的组件也必须居中)2) 你可以将组件添加到 JLabel 3) 我看不出你有什么理由不能使用中间面板,这是我经常使用的技巧。
    • 嗨@camickr。 1)你是对的,你的答案符合要求,所以我接受了。 2)哇不知道。所以我仍然没有得到 JPanel 和 JLabel 之间的区别——除了将构造函数中传递的 ImageIcon 居中。顺便说一句,它可以工作,但与您的原始答案有相同的缺点:图像居中,但覆盖在其上的组件的位置相对于显示区域,而不是图像本身。 3) 添加一个带有 BorderLayout 的中间面板并将 imagePanel 放在中心不会改变任何内容。你会建议什么布局和约束?谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-17
    • 2016-10-25
    • 2018-01-03
    • 1970-01-01
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    相关资源
    最近更新 更多