首页 > 解决方案 > GridBagLayout :组件之间的意外空间

问题描述

我尝试使用 GridBagConstraints 将组件(例如:按钮)放置在容器中。但我发现元素之间有一个空白区域。我试图修改各种参数,但找不到解决方案。

我想删除这个空白区域(例如,按钮 8 应该在按钮 4、6、7 的右侧)。

谢谢

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

public class GridBagLayout8Button { 
    public static void addComponentsToPane(Container pane) {
        pane.setLayout(new GridBagLayout());
        
        GridBagConstraints gbc1 = new GridBagConstraints();
        GridBagConstraints gbc2 = new GridBagConstraints();   
        GridBagConstraints gbc3 = new GridBagConstraints();
        GridBagConstraints gbc4 = new GridBagConstraints();
        GridBagConstraints gbc5 = new GridBagConstraints();
        GridBagConstraints gbc6 = new GridBagConstraints();
        GridBagConstraints gbc7 = new GridBagConstraints();
        GridBagConstraints gbc8 = new GridBagConstraints();
        
        JButton button1 = new JButton("1");
        gbc1.anchor = GridBagConstraints.NORTHWEST;
        gbc1.gridx = 0;
        gbc1.gridy = 0;
        gbc1.gridwidth = 1;
        gbc1.gridheight = 2;
        button1.setPreferredSize(new Dimension(46, 82));
        pane.add(button1, gbc1);

        JButton button2 = new JButton("2");
        gbc2.anchor = GridBagConstraints.NORTHWEST;
        gbc2.gridx = 1;
        gbc2.gridy = 0;
        gbc2.gridwidth=1;
        gbc2.gridheight=1;
        button2.setPreferredSize(new Dimension(118, 41));
        pane.add(button2, gbc2);
        
        JButton button3 = new JButton("3");
        gbc3.anchor = GridBagConstraints.NORTHWEST;
        gbc3.gridx = 1;
        gbc3.gridy = 1;
        gbc3.gridwidth=1;
        gbc3.gridheight=1;
        button3.setPreferredSize(new Dimension(118, 41));
        pane.add(button3, gbc3);
        
        JButton button4 = new JButton("4");
        gbc4.anchor = GridBagConstraints.NORTHWEST;
        gbc4.gridx = 2;
        gbc4.gridy = 0;
        gbc4.gridwidth = 2;
        gbc4.gridheight = 2;
        button4.setPreferredSize(new Dimension(164, 82));
        pane.add(button4, gbc4);
        
        JButton button5 = new JButton("5");  
        gbc5.anchor = GridBagConstraints.NORTHWEST;
        gbc5.gridx = 0;
        gbc5.gridy = 2;
        gbc5.gridwidth=3;
        gbc5.gridheight=2;
        button5.setPreferredSize(new Dimension(246, 82));
        pane.add(button5, gbc5);

        JButton button6 = new JButton("6");
        gbc6.anchor = GridBagConstraints.NORTHWEST;
        gbc6.gridx = 3;
        gbc6.gridy = 2;
        gbc6.gridwidth=1;
        gbc6.gridheight=1;
        button6.setPreferredSize(new Dimension(82, 41));
        pane.add(button6, gbc6);
        
        JButton button7 = new JButton("7");
        gbc7.anchor = GridBagConstraints.NORTHWEST;
        gbc7.gridx = 3;
        gbc7.gridy = 3;
        gbc7.gridwidth=1;
        gbc7.gridheight=1;
        button7.setPreferredSize(new Dimension(82, 41));
        pane.add(button7, gbc7);
        
        JButton button8 = new JButton("8");
        gbc8.anchor = GridBagConstraints.NORTHWEST;
        gbc8.gridx = 4;
        gbc8.gridy = 0;
        gbc8.gridwidth=1;
        gbc8.gridheight=4;
        button8.setPreferredSize(new Dimension (41, 164));
        pane.add(button8, gbc8);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("GridBagLayout Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                addComponentsToPane(frame.getContentPane());
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

标签: javaswinglayout-managergridbaglayout

解决方案


问题是GridBagLayout不知道如何为列分配宽度,除非至少一个组件被添加到具有“gridwidth = 1”的列中。

在这种情况下,问题出在按钮 4 和 5 之间:

  1. 按钮 4 添加到第 2 列,但网格宽度为 3,因此第 2 列实际上具有默认宽度 0。
  2. 按钮 5 尝试跨越 3 列,但其首选宽度大于 3 列的宽度。

运行代码从布局中删除按钮 4:

//pane.add(button4, gbc4);

布局被压缩。

现在查看宽度为 246 的按钮 5。

这表明前 3 列的宽度至少应为 246。

按钮 1 和 2 的宽度只有 46 和 118,总共 164,这意味着第 2 列的宽度应该是 82 (246 - 164)。

但是,GridBagLayout 使用 0 作为列的宽度。然后以某种方式在按钮 4 之后添加额外的 82 像素空间,使其与按钮 8 之间留有间隙。

解决方案是给 column2 一个最小宽度。因此,即使没有将 gridwidth =1 的组件添加到列中,也可以在计算中使用非零默认宽度。

这是通过以下代码完成的:

    //pane.setLayout(new GridBagLayout());
    GridBagLayout gbl = new GridBagLayout();
    pane.setLayout(gbl);

    //  Set up a layout with 5 columns.
    //  minimimum width of a column 2 is 82 pixels

    int[] columns = new int[5];
    columns[2] = 82;
    gbl.columnWidths = columns;

这不是一个真正的解决方案,因为它是手动尝试计算最小宽度。

这只是试图解释正在发生的事情。将最小值应用于列的概念在其他情况下可能很有用。有关此概念的工作示例,请参阅:使用 JLayeredPane 创建棋盘游戏布局。

请注意,当您使用 VGR 建议的“填充”约束时,按钮 4、6、7 的大小将额外增加 82 个像素。因此,这通过增加受影响按钮的首选宽度来解决视觉差距。

在不知道实际要求以及为什么使用这种奇怪的首选尺寸的情况下,我们无法真正给出更好的解决方案。

编辑:

按钮的大小(高度、宽度)用于表示一些值,因此保持原样很重要

那么您可能需要使用具有不同布局管理器的嵌套面板来实现您想要的布局。

例如,您可能有一个带有BorderLayout. 然后,您使用现有代码创建一个带有按钮 1-7 的面板,并将此面板添加到BorderLayout.CENTER. 然后将按钮 8 添加到BorderLayout.LINE_END.


推荐阅读