GridBagLayout的奇怪行为

3

我最近在这段代码中发现了一些奇怪的事情:

import java.awt.Color;
import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.io.IOException;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class Test {

    public static void main(String [] args) throws IOException {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();

        gbc.insets.top = 5;
        gbc.insets.right = 5;

        add(0, 0, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(2, 0, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(0, 1, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(2, 1, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(0, 2, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(1, 2, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(3, 2, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(0, 3, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(1, 3, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(3, 3, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(0, 4, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(1, 4, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(3, 4, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());
        add(0, 5, 1, 1, 4, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, panel, createPanel());

        frame.setContentPane(panel);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private static void add(int gridx, int gridy, int weightx, int weighty, int gridw, int gridh, int fill, int anchor, GridBagConstraints gbc, Container container, JComponent component) {
        gbc.gridx = gridx;
        gbc.gridy = gridy;
        gbc.weightx = weightx;
        gbc.weighty = weighty;
        gbc.gridwidth = gridw;
        gbc.gridheight = gridh;
        gbc.fill = fill;
        gbc.anchor = anchor;

        component.add(Box.createHorizontalStrut(5));
        component.add(new JLabel("(" + gridx + "; " + gridy + ")"));
        component.add(Box.createHorizontalStrut(5));
        component.add(new JLabel("gridwidth = " + gridw));
        component.add(Box.createHorizontalStrut(5));

        container.add(component, gbc);
    }

    private static JPanel createPanel() {
        JPanel panel1 = new JPanel();
        panel1.setBackground(Color.WHITE);
        panel1.setBorder(BorderFactory.createLineBorder(Color.RED));

        return panel1;
    }
}

并且在运行时的效果如下图所示:

java_weird

每个面板中都有方括号里的坐标和网格宽度。正如您从最后一行所看到的那样,全局网格宽度为4。第1列(x=0)中的第3-5行(y=2,y=3,y=4)的网格宽度为1。但是,在前两行中,第一列的网格宽度为2,并且应该在框架的中间被分割,但实际上并没有。为什么呢?


我不确定我理解使用案例或问题,但请注意,GBL通常不会为单元格分配比计算单元格实际需要的空间更多的空间。换句话说,将单元格的gridwidth增加到2可能会使单元格稍微宽一些,以容纳两个gridwidth为1且与其对齐的单元格,但其他情况则不会。另请参见为什么这个GridBagLayout看起来不像计划的那样?,该问题也面临着同样的基本问题。 - Andrew Thompson
3-3,3-3,2-2-2,2-2-2,2-2-2怎么样? - Joop Eggen
@AndrewThompson 你的意思是,如果(0; 0)单元格的宽度小于实际最小或首选宽度,它会变宽吗?只有在这种情况下吗? - SeniorJD
@JoopEggen 一样的。实际上,我在那种情况下发现了这个问题,然后尝试像我的例子一样简化,但问题仍然存在。 - SeniorJD
这是因为第一列(从0开始)没有指定宽度,因此被认为宽度为0。你也没有定义第二列的宽度。所以即使传统的解决方法也不起作用。我建议使用其他布局,比如miglayout。 - Olivier Grégoire
1个回答

1
我自己发现的内容:
public class Test {

    public static void main(String [] args) throws IOException {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        GridBagConstraints gbc = new GridBagConstraints();

        gbc.insets.top = 5;
        gbc.insets.right = 5;

        JPanel topPanel = new JPanel();
        topPanel.setLayout(new GridBagLayout());
        JPanel bottomPanel = new JPanel();
        bottomPanel.setLayout(new GridBagLayout());

        add(0, 0, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, topPanel, createPanel());
        add(1, 0, 1, 1, 2, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, topPanel, createPanel());
        add(0, 0, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, bottomPanel, createPanel());
        add(1, 0, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, bottomPanel, createPanel());
        add(2, 0, 1, 1, 1, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, bottomPanel, createPanel());
        add(0, 2, 1, 1, 3, 1, GridBagConstraints.BOTH, GridBagConstraints.CENTER, gbc, bottomPanel, createPanel());

        panel.add(topPanel);
        panel.add(bottomPanel);

        frame.setContentPane(panel);

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private static void add(int gridx, int gridy, int weightx, int weighty, int gridw, int gridh, int fill, int anchor, GridBagConstraints gbc, Container container, JComponent component) {
        gbc.gridx = gridx;
        gbc.gridy = gridy;
        gbc.weightx = weightx;
        gbc.weighty = weighty;
        gbc.gridwidth = gridw;
        gbc.gridheight = gridh;
        gbc.fill = fill;
        gbc.anchor = anchor;

        component.add(Box.createHorizontalStrut(5));
        component.add(new JLabel("(" + gridx + "; " + gridy + ")"));
        component.add(Box.createHorizontalStrut(5));
        component.add(new JLabel("gridwidth = " + gridw));
        component.add(Box.createHorizontalStrut(5));

        container.add(component, gbc);
    }

    private static JPanel createPanel() {
        JPanel panel1 = new JPanel();
        panel1.setBackground(Color.WHITE);
        panel1.setBorder(BorderFactory.createLineBorder(Color.RED));

        return panel1;
    }
}

结果看起来像:

java weird

我所做的事情:将内容面板分成两个单独的面板 - 顶部(有一个单行,其中有两个平均分配的单元格)和底部(有两行:一行有3个单元格,另一行有1个单宽单元格)。 内容面板现在具有BoxLayout而不是GBL,并且按预期工作。但我对GridBagLayout感到失望,因为它以前对我来说是完美的布局。

你不能除以3得到100的整数,...LayoutManager可以正确计算getPreferredSize,剩下的(以像素为单位)是“空边框”,这个问题在调整大小时也可能会出现,MigLayout可以正确处理。 - mKorbel
你第一行右侧没有对齐的问题吗? - Olivier Grégoire

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接