如何将空单元格添加到 GridBagLayout?

How do you add empty cells to GridBagLayout?

我想用GridBagLayout实现这个效果:

|-----------|
|  Button1  |
|-----------|
      |-----------|
      |  Button2  |
      |-----------|

我最初只是放置了按钮,但 GridBagLayout 忽略了空单元格。现在,我正在尝试使用 Box.createHorizontalStrut(10) 作为间隔符,但 GridBagLayout 正在拉伸空间以给我一个 2x2 网格。我还尝试将 JLabels 和 JPanels 作为间隔物,但我仍然得到 2x2 网格。这是我的代码:

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

public class GridBagLayoutDemo extends JFrame
{
    // class level references
    GridBagLayout layout;   
    JButton button1, button2;

    // constructor
    public GridBagLayoutDemo()
    {
        super("GridBagLayout Demo");

        layout = new GridBagLayout();
        setLayout( layout );

        // create components
        button1 = new JButton("Button 1");
        button2 = new JButton("Button 2");

        // components should be resized vertically AND horizontally (BOTH) to fill given area
        int fill = GridBagConstraints.BOTH;

        // if you do not fill the area, where should the component go?
        int anchor = GridBagConstraints.CENTER;

        // place components on the frame using a method
        placeComponent( button1, 0, 0, 2, 2, 0.5, 0.5, fill, 0, 0, 0, 0, anchor );
        placeComponent( Box.createHorizontalStrut(5), 2, 0, 1, 2, 0.5, 0.5, fill, 0, 0, 0, 0, anchor );
        placeComponent( Box.createHorizontalStrut(5), 0, 2, 1, 2, 0.5, 0.5, fill, 0, 0, 0, 0, anchor );
        placeComponent( button2, 1, 2, 2, 2, 0.5, 0.5, fill, 0, 0, 0, 0, anchor );
    }

    /// Place the component on the GridBag with appropriate parameters
    private void placeComponent( Component comp, int column, int row, int width, int height, double weightX, double weightY, 
            int fill, int marginTop, int marginLeft, int marginBottom, int marginRight, int anchor )
    {
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.gridx = column;     // column to start
        constraints.gridy = row;        // row to start
        constraints.gridwidth = width;  // number of cells wide
        constraints.gridheight = height;  // number of cells tall
        constraints.weightx = weightX;    // when size is changed, grow in x direction
        constraints.weighty = weightY;    // when size is changed, grow in y direction
        constraints.fill = fill;        // should the component fill the given area?  GridBagConstraints.NONE, GridBagConstraints.BOTH, GridBagConstraints.CENTER, etc
        constraints.insets = new Insets( marginTop, marginLeft, marginBottom, marginRight );
        constraints.anchor = anchor;
        layout.setConstraints(comp, constraints);
        add(comp);  // place component on the frame with these parameters
    }

    /// launches the application
    public static void main(String[] args)
    {
        GridBagLayoutDemo app = new GridBagLayoutDemo();
        app.setSize(400, 300);
        app.setLocationRelativeTo(null);
        app.setVisible(true);
    }
}

有什么想法吗?谢谢!

原始答案

您可以使用 GridBagConstraints.INSETS 来实现。在你的代码中,我看到你总是将 0 传递给你的 placeComponent 方法,你只需要指定一个不同的值。 不需要 Horizo​​ntalStruct 或其他组件。

例如,在您的代码中,如果您使用:

placeComponent( button1, 0, 0, 2, 2, 0.5, 0.5, fill, 10, 10, 10, 10, anchor);
placeComponent( button2, 1, 2, 2, 2, 0.5, 0.5, fill, 50, 100, 10, 10, anchor);

您将获得:

请注意,由于您使用 GridBagLayout 作为内容窗格布局,因此按钮会按 window 大小展开。

如果您不希望 button2 小于 button1,可以使用 GridBagConstraints.NONE 作为填充参数来避免这种情况。

编辑

我根据您在下面的评论编辑了我的答案。

当然可以避免使用 GridBagLayout.NONE。

这完全取决于您想要实现的目标。 因此,您希望您的按钮具有相同的大小,并且当您调整 window 大小时它们的大小会增加。还行吧。 但是你的button2应该怎么在button1的右边"shifted"呢?按指定像素数?

如果是这样,假设 button2 应该相对于 button1 向右移动 100 像素。 这可以通过将第二个按钮的左插入设置为 100,并将第一个按钮的右插入设置为 100(以保持相同的大小)来轻松实现。

如果您在代码中替换了这四行:

placeComponent( button1, 0, 0, 2, 2, 0.5, 0.5, fill, 0, 0, 0, 0, anchor );
placeComponent( Box.createHorizontalStrut(5), 2, 0, 1, 2, 0.5, 0.5, fill, 0, 0, 0, 0, anchor );
placeComponent( Box.createHorizontalStrut(5), 0, 2, 1, 2, 0.5, 0.5, fill, 0, 0, 0, 0, anchor );
placeComponent( button2, 1, 2, 2, 2, 0.5, 0.5, fill, 0, 0, 0, 0, anchor );

有:

placeComponent( button1, 0, 0, 2, 2, 0.5, 0.5, fill, 0, 0, 0, 100, anchor );
placeComponent( button2, 1, 2, 2, 2, 0.5, 0.5, fill, 50, 100, 0, 0, anchor );

你会得到这样的结果:

这将是您调整后的尺寸 window:

如果这不是您想要实现的,您最好提供 ASCII 艺术图或所需 GUI 的简单绘图,尺寸最小,宽度和高度更大。

希望对您有所帮助!

GridBagLayout 根据第一个词的含义进行工作;一个网格。为了达到上面你想要的效果,你其实需要一个2x3的网格:

        c1   | c2 |   c3
             |    |  
             v    v   
     |------------|
r1   |    B1      |  <S1>
     |------------|
---->
             |------------|
r2     <S2>  |    B2      |
             |------------|

2x1或2x2的网格无法实现想要的偏移效果(如果你想在按钮上重叠)。我们需要第三列以获得重叠的按钮。

在此范例中,您具有以下内容:

comp    | x    | y    | w    | h
------------------------------------
B1      | 0    | 0    | 2    | 1
S1      | 2    | 0    | 1    | 1
S2      | 0    | 1    | 1    | 1
B2      | 1    | 1    | 2    | 1

基本上就是说B1占[r1,c1-c2],S1占[r1,c3],S2占[r2,c1],B2占[r2,c2-c3]。希望清楚。

这里有一个 MCVE 说明了如何实现这一点。您可以毫不费力地将它应用到您的代码中:

public class StaggerTest {
  public static void main(String[] args) {
    JFrame frame = new JFrame("Stagger Test");
    frame.setSize(600, 600);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel panel = new JPanel(new GridBagLayout());

    placeComp(new JButton("1"), panel, 0, 0, 2, 1);
    placeComp(Box.createHorizontalStrut(10), panel, 2, 0, 1, 1);
    placeComp(Box.createHorizontalStrut(10), panel, 0, 1, 1, 1);
    placeComp(new JButton("2"), panel, 1, 1, 2, 1);

    frame.setContentPane(panel);

    frame.setVisible(true);
  }

  public static void placeComp(Component comp, JPanel panel, int x, int y, int w, int h) {
    GridBagConstraints cons = new GridBagConstraints();
    cons.gridx = x;
    cons.gridy = y;
    cons.gridwidth = w;
    cons.gridheight = h;
    panel.add(comp, cons);
  }
}

根据您的用例,也可以使用其他答案中提到的插图。

我要提醒的一件事是,如果面板的布局本质上是动态的,您可能希望级联面板和面板内的布局。例如,将给定的示例扩展为:

|-----------|
|  Button1  |
|-----------|
      |-----------|
      |  Button2  |
      |-----------|
            |-----------|
            |  Button3  |
            |-----------|

等等,用单个面板处理会变得有点混乱(特别是如果需要动态处理;IE:当事件 X 发生时添加按钮 4)。 insets 方法可以更好地解决这个问题;您可以简单地迭代插入值。

IMO,更好的方法是级联您的面板,以便每一行都由其自己的面板(和布局管理器)管理。

+-------MAIN PANEL----------+
| +------c1-----R1 PANEL---+|
| ||-----------|           ||
r1||  Button1  |           ||
| ||-----------|           ||
| +------------------------+|
| +---c1--------c2-R2 PANEL+|
| |       |-----------|    ||
r2|<STRUT>|  Button1  |    ||
| |       |-----------|    ||
| +------------------------+|
|  etc...                   |
+---------------------------+

希望对您有所帮助!