微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

GridBagLayout:组件之间的意外空间

如何解决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);
            }
        });
    }
}

解决方法

问题是 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;

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

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

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

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

编辑:

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

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

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

,

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

您想要的是将 fill 约束设置为 BOTH。例如:

gbc1.fill = GridBagConstraints.BOTH;

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

如果您希望按钮更大,您可以change its margin,或者您可以使用ipadxipady 约束,它们会增加组件在布局中的默认大小。

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

,

这是我想出的 GUI。

GridBagLayout Test

我必须创建两个单独的 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));
        
        addPanel(panel,createUpperPanel(),1,1);
        addPanel(panel,createLowerPanel(),1);
        createJButton(panel,"8",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",2);
        createJButton(panel,"2",2,"3",1); 
        createJButton(panel,"4",3,2);
        
        return panel;
    }
    
    private JPanel createLowerPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        
        createJButton(panel,"5",4,"6","7",1);
        
        return panel;
    }

    private void createJButton(JPanel panel,String value,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);
    }

}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。