【问题标题】:How do you add empty cells to GridBagLayout?如何将空单元格添加到 GridBagLayout?
【发布时间】:2017-07-18 19:19:14
【问题描述】:

我想用GridBagLayout来实现这个效果:

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

我最初只是放置了按钮,但 GridBagLayout 忽略了空单元格。现在,我正在尝试使用 Box.createHorizo​​ntalStrut(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);
    }
}

有什么想法吗?谢谢!

【问题讨论】:

  • GBC 是基于列的布局管理器,也许自定义 TableLayout 比 GBC 更好,特别是简单,甚至可以使用 SpringLayout(列和行)

标签: java swing constraints layout-manager gridbaglayout


【解决方案1】:

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...                   |
+---------------------------+

希望有帮助!

【讨论】:

  • 感谢您的解释。这就是我期望发生的事情。但是,当您使用 cons.weightx = 0.5、cons.weighty = 0.0 和 GridBagConstraints.BOTH 填充表单时,表单会提供 2x2 网格而不是预期的 3x3 网格。看起来我可能不得不使用 Insets 或完全不同的布局管理器来实现我想要的目标。
  • @Birdman 对,在您的示例中,这将演变为 2x2。您正在对 4 个不同的组件应用相等的权重,这些组件的排列方式使得 2 列每列包含单位。这将导致 c2(在我的示例中)完全折叠并设置为 0 大小。为什么要对垫片进行加权?
  • @Birdman 如果你这样做placeComponent( Box.createHorizontalStrut(5), 2, 0, 1, 2, 0, 0, fill, 0, 0, 0, 0, anchor );(对于另一个支柱也是如此),你最终会更接近你想要的效果(因为会发生相反的情况;只有存在于 c2 中的组件才会请求额外的空间,所以 c2 会吃掉 ALL 的额外空间。
  • 另外请注意,我只是假设我在上面所说的是真的;我目前不在可以运行您的代码的环境中,因此无法对其进行测试。我确实通过修改我的测试代码以考虑加权/填充来尝试它,尽管按照我说的做它工作正常。如果您尝试这样做,但它不起作用,只需 LMK 您所看到的。
  • 如果我使用 0,0 作为 weightx,重量,按钮保持小。我可以使用 Toolkit 获取用户的屏幕分辨率,并根据分辨率调整帧大小。但是,如果我使用 0,0 作为 weightx,weighty,则按钮在更高分辨率的屏幕上很小。这是我在左侧使用 0,0 并在右侧使用目标模型时的结果。谢谢您的帮助! rickbird.com/downloads/GridBagLayout_Result.jpg
【解决方案2】:

原始答案

您可以通过使用 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 作为内容窗格布局,因此按钮会根据您的窗口大小进行扩展。

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

编辑

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

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

这完全取决于您想要实现的目标。 因此,您希望按钮具有相同的大小,并且在调整窗口大小时它们的大小会增加。还行吧。 但是您的 button2 应该如何在 button1 的右侧“移动”?按指定的像素数?

如果是这样,假设 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 );

你会得到这样的结果:

这将是您调整大小的窗口:

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

希望这会有所帮助!

【讨论】:

  • 有没有办法在不使用 GridBagConstraints.NONE 的情况下解决这个问题?我想使用 GridBagConstraints.BOTH 这样按钮的大小会随着框架的增大而增大。例如,如果有人使用分辨率为 1280x800 的显示器,他们将获得与使用分辨率为 2560x1600 的显示器不同的体验。我可以使用 Toolkit 根据分辨率调整框架的大小,但 NONE 会使所有内容都非常小。感谢您的帮助!
  • @Birdman 我已根据您的评论编辑了我的答案。如果这不是您想要的,请提供更多详细信息。
  • Ansharja,感谢您的帮助。看起来我需要使用插图来模仿我想要的效果。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多