网格包布局(GridBagLayout)无法正常工作

5

我想创建以下GUI:

enter image description here

但是我创建的GUI是:

enter image description here

我的网格布局如下:

图像链接:THE GRIDLAYOUT FOR THIS

我不明白为什么代码运行后会得到这个输出结果。我画了一张图来辅助编写代码,看上去应该没问题。

方法"addComp"将给定的输入组件添加到指定位置(x, y)和指定的组件宽度和高度的输入面板中。

代码:

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

public class GUIError extends JFrame {

    //initialise all the components
    JPanel mainPanel = new JPanel();
    JTextField txtDisplay = new JTextField();
    JButton btnA = new JButton("A");
    JButton btnB = new JButton("B");
    JButton btnC = new JButton("C");
    JButton btnD = new JButton("D");
    JButton btnE = new JButton("E");
    JButton btnF = new JButton("F");
    JButton btnWA = new JButton("WA");
    JButton btnWB = new JButton("WB");
    JButton btnWC = new JButton("WC");
    JButton btnWD = new JButton("WD");

    private void addComp(JPanel panel, JComponent comp, int xPos, int yPos, int compWidth, int compHeight) {

        GridBagConstraints gridConstraints = new GridBagConstraints();

        gridConstraints.gridx = xPos;
        gridConstraints.gridy = yPos;
        gridConstraints.gridwidth = compWidth;
        gridConstraints.gridheight = compHeight;
        gridConstraints.weightx = 0.5;
        gridConstraints.weighty = 0.5;
        gridConstraints.insets = new Insets(5, 5, 5, 5);
        gridConstraints.anchor = GridBagConstraints.CENTER;
        gridConstraints.fill = GridBagConstraints.BOTH;

        panel.add(comp, gridConstraints);

    }


    public static void main(String[] args) {
        try {
            for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        }
        catch (Exception e) { }

        SwingUtilities.invokeLater(new Runnable() {

            public void run() {

                // create frame
                JFrame frame = new JFrame("Calculator");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.setLocationRelativeTo(null);
                Container c = frame.getContentPane();

                // create GUI within frame              
                new GUIError(c);

                // finish frame definition
                frame.pack();
                frame.setResizable(false);
                frame.setVisible(true);

            }

        });
    }

    public GUIError(Container cont) {

        cont.setPreferredSize(new Dimension(610, 250));

        // parent panel containes every other panel
        mainPanel.setLayout(new GridBagLayout());

        // text display
        txtDisplay.setEditable(false);
        addComp(mainPanel, txtDisplay, 0, 0, 12, 2); // width 16, height 2


        addComp(mainPanel, btnA, 0, 2, 2, 1);
        addComp(mainPanel, btnB, 2, 2, 2, 1);
        addComp(mainPanel, btnC, 4, 2, 2, 1);
        addComp(mainPanel, btnD, 6, 2, 2, 1);
        addComp(mainPanel, btnE, 8, 2, 2, 1);
        addComp(mainPanel, btnF, 10, 2, 2, 1);
        addComp(mainPanel, btnWA, 0, 3, 3, 1);
        addComp(mainPanel, btnWB, 3, 3, 3, 1);
        addComp(mainPanel, btnWC, 6, 3, 3, 1);
        addComp(mainPanel, btnWD, 9, 3, 3, 1);

        cont.add(mainPanel);
    }
}

1
GBC是基于列的,+1表示问题和SSCCE/MCVE,这就是为什么MigLayout(例如)被开发的原因。 - mKorbel
不要以为只用一个面板就能实现这个。据我所知,gridwidth 无法指定“半个网格”。我认为最好的选择是使用不同的布局,或将组件分成不同的面板(主面板在顶部包含一个字段,在下面有两个面板(并排)。每个子面板都有两个面板:一个用于三个较小的按钮,另一个下面有两个更大的按钮)。 - Dioxin
我没有使用gridwidth指定半个网格。第一行按钮的gridwidth为2,第三行按钮的gridwidth为3。我不明白您所说的底部3个较小和2个较大的按钮是什么意思?我链接的网格显示了我在此情况下使用的网格。第二行按钮大小相同,第三行按钮大小也相同。我不明白为什么这不能与GridBagLayout一起使用。 - user3749872
@user3749872 看看你要求的结果;你想让 WAWB 占据与其他三个按钮相同的空间。正如你所看到的结果,你的组件似乎锁定在原位(与其他所有东西对齐)。由于你的小按钮,你有6个网格空间;你希望 WA 占据下面1 1/2个网格空间,WB 占据另外1 1/2个网格空间(WC和WD也是如此)。在代码中,你没有尝试占据半个网格,但你要求的结果需要这样做。这可以通过切换布局或使用面板进行分离来完成。 - Dioxin
我会发布一个解释答案以及解决方案的回复。请稍等一下。 - Dioxin
@mKorbel,您能详细说明一下_GBC是基于列的_吗?这听起来像是我注意到的一个问题的解释... - Matthieu
4个回答

5
这可以很容易地通过使用GridBagLayout来实现,就像下面呈现的示例一样。您只需要为每个ROW分别使用两个JPanel,并使用GridBagLayout将组件添加到第一行中,其中weightx = 0.16,因为每个JButton应占据这么多的区域,对于第二行,weightx = 0.25,因为这是每个JButton沿着X方向所占据的区域。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class GridBagExample {
    private static final int SIZE = 10;
    private JButton[] buttons;
    private GridBagConstraints gbc;

    public GridBagExample() {
        buttons = new JButton[SIZE];
        gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
    }

    private void createAndDisplayGUI() {
        JFrame frame = new JFrame("Grid Game");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel contentPane = new JPanel();
        contentPane.setLayout(new GridLayout(2, 1, 5, 5));
        contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        JPanel topPanel = new JPanel();
        JTextField textField = new JTextField(10);
        //topPanel.add(textField);

        JPanel buttonPanel = new JPanel(new GridLayout(2, 1, 5, 5));
        JPanel headerPanel = new JPanel(new GridBagLayout());
        buttons[0] = new JButton("A");
        addComp(headerPanel, buttons[0], 0, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);        
        buttons[1] = new JButton("B");
        addComp(headerPanel, buttons[1], 1, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[2] = new JButton("C");
        addComp(headerPanel, buttons[2], 2, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[3] = new JButton("D");
        addComp(headerPanel, buttons[3], 3, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[4] = new JButton("E");
        addComp(headerPanel, buttons[4], 4, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[5] = new JButton("F");
        addComp(headerPanel, buttons[5], 5, 0, 0.16, 1.0, 1, 1, GridBagConstraints.BOTH);

        JPanel footerPanel = new JPanel(new GridBagLayout());
        buttons[6] = new JButton("WA");
        addComp(footerPanel, buttons[6], 0, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[7] = new JButton("WB");
        addComp(footerPanel, buttons[7], 1, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[8] = new JButton("WC");
        addComp(footerPanel, buttons[8], 2, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttons[9] = new JButton("WD");
        addComp(footerPanel, buttons[9], 3, 0, 0.25, 1.0, 1, 1, GridBagConstraints.BOTH);
        buttonPanel.add(headerPanel);
        buttonPanel.add(footerPanel);

        contentPane.add(textField);
        contentPane.add(buttonPanel);

        frame.setContentPane(contentPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private void addComp(JPanel panel, JComponent comp, int x, int y,
                                    double wx, double wy, int gw, int gh, int fill) {
        gbc.gridx = x;
        gbc.gridy = y;
        gbc.weightx = wx;
        gbc.weighty = wy;
        gbc.gridwidth = gw;
        gbc.gridheight = gh;
        gbc.fill = fill;

        panel.add(comp, gbc);
    }

    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new GridBagExample().createAndDisplayGUI();
            }
        });
    }
}

输出结果: 网格袋布局:

gridbagexample

如果在这种情况下不需要使用 GridBagLayout,则可以通过 GridLayout 实现相同的输出,如下所示:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class GridBagExample {
    private static final int SIZE = 10;
    private JButton[] buttons;

    public GridBagExample() {
        buttons = new JButton[SIZE];
    }

    private void createAndDisplayGUI() {
        JFrame frame = new JFrame("Grid Game");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        JPanel contentPane = new JPanel();
        contentPane.setLayout(new GridLayout(2, 1, 5, 5));
        contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        JPanel topPanel = new JPanel();
        JTextArea tArea = new JTextArea(5, 30);
        JScrollPane scroller = new JScrollPane();
        scroller.setViewportView(tArea);
        topPanel.add(scroller);

        JPanel buttonPanel = new JPanel(new GridLayout(2, 1, 5, 5));
        JPanel headerPanel = new JPanel(new GridLayout(1, 0, 5, 5));
        buttons[0] = new JButton("A");
        headerPanel.add(buttons[0]);
        buttons[1] = new JButton("B");
        headerPanel.add(buttons[1]);
        buttons[2] = new JButton("C");
        headerPanel.add(buttons[2]);
        buttons[3] = new JButton("D");
        headerPanel.add(buttons[3]);
        buttons[4] = new JButton("E");
        headerPanel.add(buttons[4]);
        buttons[5] = new JButton("F");
        headerPanel.add(buttons[5]);
        JPanel footerPanel = new JPanel(new GridLayout(1, 0, 5, 5));
        buttons[6] = new JButton("WA");
        footerPanel.add(buttons[6]);
        buttons[7] = new JButton("WB");
        footerPanel.add(buttons[7]);
        buttons[8] = new JButton("WC");
        footerPanel.add(buttons[8]);
        buttons[9] = new JButton("WD");
        footerPanel.add(buttons[9]);
        buttonPanel.add(headerPanel);
        buttonPanel.add(footerPanel);

        contentPane.add(topPanel);
        contentPane.add(buttonPanel);

        frame.setContentPane(contentPane);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new GridBagExample().createAndDisplayGUI();
            }
        });
    }
}

输出: 网格布局: GridBagExample


5

通常我会制作单独的面板,但是嘿,谁不喜欢挑战呢?

问题在于,某些列对GBL(全局线路板)来说没有明确定义(没有单个组件定义其宽度),因此按钮 WA 不知道需要延伸多远才能覆盖按钮 B 的一半等。

所以,在构成所需区域的列中添加了一些零宽度间隔。

所有内容都在一个面板中:

enter image description here

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

public class GridBagDemo3 implements Runnable
{
  private JPanel panel;

  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new GridBagDemo3());
  }

  public void run()
  {
    JTextArea text = new JTextArea(10,10);
    JButton btnA = new JButton("A");
    JButton btnB = new JButton("B");
    JButton btnC = new JButton("C");
    JButton btnD = new JButton("D");
    JButton btnE = new JButton("E");
    JButton btnF = new JButton("F");
    JButton btnWA = new JButton("WA");
    JButton btnWB = new JButton("WB");
    JButton btnWC = new JButton("WC");
    JButton btnWD = new JButton("WD");

    panel = new JPanel(new GridBagLayout());

    add(text,   0,0, 12,1);
    add(btnA,   0,1, 2,1);
    add(btnB,   2,1, 2,1);
    add(btnC,   4,1, 2,1);
    add(btnD,   6,1, 2,1);
    add(btnE,   8,1, 2,1);
    add(btnF,  10,1, 2,1);
    add(btnWA,  0,2, 3,1);
    add(btnWB,  3,2, 3,1);
    add(btnWC,  6,2, 3,1);
    add(btnWD,  9,2, 3,1);

    // SPACERS: define the 2 columns that button B spans
    //          so that WA and WB can split B, and same for button E
    add(null,   2,2, 1,1);
    add(null,   3,2, 1,1);
    add(null,   8,2, 1,1);
    add(null,   9,2, 1,1);

    JFrame frame = new JFrame("Grig Bag");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(panel);
    frame.pack();
    frame.setVisible(true);
  }

  private void add(Component comp, int x, int y, int colspan, int rowspan)
  {
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx = x;
    gbc.gridy = y;
    gbc.gridwidth = colspan;
    gbc.gridheight = rowspan;
    gbc.weighty = .1;
    gbc.anchor = GridBagConstraints.CENTER;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.insets = new Insets(5,5,5,5);

    if (comp != null)
    {
      gbc.weightx = 1;
    }
    else
    {
      comp = Box.createHorizontalGlue();
      gbc.fill = GridBagConstraints.NONE;
      gbc.weightx = 0.1;
      gbc.weighty = 0;
    }

    panel.add(comp, gbc);
  }
}

4

@Matthieu写道 -

你能详细解释一下GBC是列为基础的吗?听起来像是我注意到的一个问题的解释...

我认为这是GridBagLayout设计的方式,我总是将JLabels(没有边框:-)用作矩阵...

enter image description here

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

public class CopyTextNorthPanel extends JPanel {

    private static final long serialVersionUID = 1L;
    private JLabel hidelLabel;
    private JLabel firstLabel;
    private JTextField firstText;

    public CopyTextNorthPanel() {

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
        for (int k = 0; k < 50; k++) {
            hidelLabel = new JLabel("     ");
            hidelLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.weightx = 0.5;
            gbc.weighty = 0.5;
            gbc.gridx = k;
            gbc.gridy = 0;
            add(hidelLabel, gbc);
        }
        for (int k = 0; k < 5; k++) {
            firstLabel = new JLabel("Testing Label : ", SwingConstants.RIGHT);
            firstLabel.setFont(new Font("Serif", Font.BOLD, 20));
            firstLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 0;
            gbc.gridwidth = 8;
            gbc.gridy = k + 1;
            add(firstLabel, gbc);
        }
        for (int k = 0; k < 5; k++) {
            firstText = new JTextField("Testing TextField");
            firstText.setFont(new Font("Serif", Font.BOLD, 20));
            firstText.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 9;
            gbc.gridwidth = k + 8;
            gbc.gridy = k + 1;
            add(firstText, gbc);
        }
        for (int k = 0; k < 5; k++) {
            firstLabel = new JLabel("Testing Label : ", SwingConstants.RIGHT);
            firstLabel.setFont(new Font("Serif", Font.BOLD, 20));
            firstLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 20 + k;
            gbc.gridwidth = 8;
            gbc.gridy = k + 1;
            add(firstLabel, gbc);
        }
        for (int k = 0; k < 5; k++) {
            firstText = new JTextField("Testing TextField");
            firstText.setFont(new Font("Serif", Font.BOLD, 20));
            firstText.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(0, 0, 5, 0);
            gbc.gridx = 29 + k;
            gbc.gridwidth = 21 - k;
            gbc.gridy = k + 1;
            add(firstText, gbc);
        }
    }
}

3
如果你仍然想了解你的错误: 'grid'布局不是FlowLayout,你不能简单地添加组件,然后程序就会立即绘制对象。在网格的情况下,虚拟机首先读取所有对象,然后构建网格,列数的数量基于那些具有最大列数的行。因此,你有一个很好的想法,选择12列(这样你就避免了创建新的“面板”并节省了系统资源),但是要做到正确,你只需要在其中一行中添加12个空间(不仅是空的,还应该大小为零)。
    // text display
    txtDisplay.setEditable(false);
    addComp(mainPanel, txtDisplay, 0, 0, 12, 2); // width 16, height 2



    //now go with empty spaces
    for(int i=0;i<12;i++){
        GridBagConstraints gridConstraints = new GridBagConstraints();
        gridConstraints.gridx = i;    //12 times "i"
        gridConstraints.gridy = 1;  //you left y=1 empty, so why don't use it
        gridConstraints.gridwidth = 1;  //one column = one space in grid
        gridConstraints.gridheight = 0;  //we don't want it to occupied any space
        gridConstraints.weightx = 0.5;
        gridConstraints.weighty = 0.5;
        gridConstraints.insets = new Insets(0, 0, 0, 0); //same reason, we don't want it to occupied any space
        gridConstraints.anchor = GridBagConstraints.CENTER;
        gridConstraints.fill = GridBagConstraints.BOTH ;

        mainPanel.add(Box.createHorizontalGlue(), gridConstraints);
    }


    addComp(mainPanel, btnA, 0, 2, 2, 1);
    addComp(mainPanel, btnB, 2, 2, 2, 1);
    addComp(mainPanel, btnC, 4, 2, 2, 1);
    addComp(mainPanel, btnD, 6, 2, 2, 1);
    addComp(mainPanel, btnE, 8, 2, 2, 1);
    addComp(mainPanel, btnF, 10, 2, 2, 1);
    addComp(mainPanel, btnWA, 0, 3, 3, 1);
    addComp(mainPanel, btnWB, 3, 3, 3, 1);
    addComp(mainPanel, btnWC, 6, 3, 3, 1);
    addComp(mainPanel, btnWD, 9, 3, 3, 1);

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