【问题标题】:GridBagLayout : unexpected space between componentGridBagLayout :组件之间的意外空间
【发布时间】:2021-03-15 20:24:48
【问题描述】:

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

【问题讨论】:

    标签: java swing layout-manager gridbaglayout


    【解决方案1】:

    问题在于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

    【讨论】:

    • 非常感谢您非常准确和详细的解释。它有助于理解错误。在我的例子中,按钮的大小(高度、宽度)用于表示一些值,因此保持原样很重要。
    • 我尝试编写代码来创建 JButton 面板。我必须为每个 JButton 指定一个首选大小,并且我必须将 JButton 分成上 JPanel (1 - 4)、下 JPanel (5 - 7) 和右 JButton,以使按钮的大小稍微正确。
    【解决方案2】:

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

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

    gbc1.fill = GridBagConstraints.BOTH;
    

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

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

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

    【讨论】:

    • @user15358848 当然可以,但是如果布局管理器被覆盖,则无法使用正确的默认大小。
    • 感谢您的建议。但是,就我而言,按钮的大小很重要,因为它代表了我的应用程序中的某些内容。设置:gbc1.fill = GridBagConstraints.BOTH;也会改变按钮的大小。
    【解决方案3】:

    这是我想出的 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);
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2017-12-17
      • 2021-05-26
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      • 2019-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多