GridBagLayout:组件之间出现意外 space

GridBagLayout : unexpected space between component

我尝试使用 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);
            }
        });
    }
}

不要使用 setPreferredSize。您正在干扰布局正确放置组件的能力。

你想要的是设置fill constraint to BOTH。例如:

gbc1.fill = GridBagConstraints.BOTH;

这将导致 button1 填满它的单元格。对每个约束对象重复此操作。

如果您希望按钮更大,可以 change its margin, or you can use the ipadx and ipady 约束,这会增加组件在布局中的默认大小。

旁注:您对 setPreferredSize 的使用使我无法在最右边的按钮中看到“8”。字体在不同的计算机上呈现不同。这就是为什么您通常希望让组件报告其自己的首选大小。

问题是 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 作为列宽。这不知何故然后添加额外的 82 像素 space 在按钮 4 之后离开它和按钮 8.

解决办法是给column2一个最小宽度。因此,即使没有将网格宽度 =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;

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

这只是试图解释正在发生的事情。将最小值应用于列的概念在其他情况下可能很有用。请参阅: 此概念的工作示例。

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

在不知道实际需求以及为什么使用如此奇怪的首选尺寸的情况下,我们无法真正提供更好的解决方案。

编辑:

the size of the buttons (height, width) is used to represent somes values, so it's important to maintain as they are

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

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

这是我想出的 GUI。

我不得不创建两个单独的 JPanels。一个 JPanel 用于 1 - 4 JButtons 和一个 JPanel 用于 5 - 7 JButtons.

我必须为每个 JButton 设置一个首选大小。我制作了一个 60 x 40 像素的 1 x 1 按钮。

这是完整的可运行代码。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class GridBagLayout8Button {
    
    public static void main(String[] args) {
        GridBagLayout8Button gbb = new GridBagLayout8Button();
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("GridBagLayout Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(gbb.createMainPanel(), BorderLayout.CENTER);
                frame.pack();
                frame.setLocationByPlatform(true);
                frame.setVisible(true);
            }
        });
    }
    
    public JPanel createMainPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        
        addPanel(panel, createUpperPanel(), 0, 0, 1, 1);
        addPanel(panel, createLowerPanel(), 0, 1, 1, 1);
        createJButton(panel, "8", 1, 0, 1, 2);
        
        return panel;
    }
    
    private void addPanel(JPanel panel, JPanel innerPanel, int gridx, int gridy,
            int gridwidth, int gridheight) {
         GridBagConstraints gbc = new GridBagConstraints();
         gbc.anchor = GridBagConstraints.LINE_START;
         gbc.fill = GridBagConstraints.BOTH;
         gbc.gridx = gridx;
         gbc.gridy = gridy;
         gbc.gridwidth = gridwidth;
         gbc.gridheight = gridheight;
         
         panel.add(innerPanel, gbc);
    }
    
    private JPanel createUpperPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        
        createJButton(panel, "1", 0, 0, 1, 2);
        createJButton(panel, "2", 1, 0, 2, 1);
        createJButton(panel, "3", 1, 1, 2, 1); 
        createJButton(panel, "4", 3, 0, 3, 2);
        
        return panel;
    }
    
    private JPanel createLowerPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        
        createJButton(panel, "5", 0, 2, 4, 2);
        createJButton(panel, "6", 4, 2, 2, 1);
        createJButton(panel, "7", 4, 3, 2, 1);
        
        return panel;
    }

    private void createJButton(JPanel panel, String value, int gridx, int gridy,
            int gridwidth, int gridheight) {
        JButton button = new JButton(value);
        Dimension d = new Dimension(gridwidth * 60, gridheight * 40);
        button.setPreferredSize(d);
 
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.anchor = GridBagConstraints.LINE_START;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridx = gridx;
        gbc.gridy = gridy;
        gbc.gridwidth = gridwidth;
        gbc.gridheight = gridheight;
        
        panel.add(button, gbc);
    }

}