Java Swing GridBagLayout组件定位

3
我第一次使用 Swing 的 GridBagLayout,并且目前只向容器中添加了两个组件,尽管我打算在垂直方向上添加更多组件。到目前为止,第一个组件(一个 JLabel)在 PAGE_START 正确地定位,而且我已经记得为组件对应的 GridBagConstraints 设置权重属性。然而,第二个组件(一个 JTextField)没有按照我想要的方式定位,而是居中于容器,而不是在 JLabel 下面移动。我尝试使用多个锚定常量,包括 FIRST_LINE_START、PAGE_START、NORTH 和 NORTHWEST,但目前什么都没用。

因此,我再次呼吁 stackoverflow 的有才华的程序员们帮助解决问题。下面是代码片段,下面是问题的图形化图像。

    // Instantiate components and configure their corresponding GridBagConstraints attributes
    // refPlusType properties
    refPlusType = new JLabel("<html><h3>"+"Reference"+" - "+"Job Type"+" </h3><hr /></html>");
    refPlusTypeGC = new GridBagConstraints();
    refPlusTypeGC.gridx = 0; // Grid position 
    refPlusTypeGC.gridy = 0;
    refPlusTypeGC.gridwidth = 2; // Number of colums occupied by component
    refPlusTypeGC.insets = new Insets(5, 10, 5, 10); // Specifies margin
    refPlusTypeGC.weightx = 0.1; // Required for anchor to work. 
    refPlusTypeGC.weighty = 0.1; // Required for anchor to work. 
    refPlusTypeGC.anchor = GridBagConstraints.PAGE_START; // Position in container

    // addressLine1 properties
    addressLine1 = new JTextField();
    addressLine1GC = new GridBagConstraints();
    addressLine1GC.gridx = 0; 
    addressLine1GC.gridy = 1;
    addressLine1GC.gridwidth = 2; 
    addressLine1GC.insets = new Insets(0, 10, 0, 10); 
    addressLine1GC.fill = GridBagConstraints.HORIZONTAL; // Specifies component fill Horizontal space
    addressLine1GC.weightx = 0.1; 
    addressLine1GC.weighty = 0.1; 
    addressLine1GC.anchor = GridBagConstraints.FIRST_LINE_START;

    // Add components to this HALLogisticsDetailsPanel
    this.add(refPlusType, refPlusTypeGC);
    this.add(addressLine1, addressLine1GC);

下面是图片;

在此输入图片描述

非常感谢您提供的任何帮助。


如果你删除了weighty的值会发生什么?只保留weightx的值会怎样? - nIcE cOw
addressLine1GC.anchor = GridBagConstraints.NORTH; - Guillaume Polet
如果我去掉weighty,那么两个元素会聚集在容器的中心,而不是顶部。anchor NORTH已经按照问题中指定的方式尝试过了,但结果没有改变。 - Rudi Kershaw
与其学习令人讨厌的GridBag,不如选择三大第三方管理器之一(MigLayout、FormLayout、DesignGridBagLayout - 第一个是我目前个人最喜欢的)- 它们都更易于使用且功能更强大。 - kleopatra
1
我听说FormLayout很不错,而且我知道第三方布局管理器在许多情况下都要好得多,但我还没有掌握Java标准布局。一旦我掌握了基础知识,我会更愿意转向第三方解决方案。如果现在就转向第三方解决方案,我感觉我可能永远也掌握不了其他标准布局的技巧。 - Rudi Kershaw
显示剩余3条评论
4个回答

4
尝试将addressLine1weighty增加到更大的值。我进行了一次快速测试,将它设置为1000:
addressLine1GC.weighty = 1000.0;

这导致addressLine1字段被推到标签下方并且有一定的空白。


谢谢Bryan。我将它设置为100,这样就可以了。我不禁感到“权重”属性有点难以理解。如果这意味着每次都必须手动设置一个更高的值,那么这将是一件非常痛苦的事情,但我想已经做完了就算了。 - Rudi Kershaw
看起来在总体上不会起作用,因为我每次都必须将 weighty 增加 *1000,这意味着在我的一半组件之前,我就会用完 double 数字。 - Rudi Kershaw
是的,那会是个问题。看起来Guillaume有一个更好的答案,利用了anchor = NORTH以及稍微修改了weightx和weighty的值。 - Bryan Hutchinson

2

anchor = NORTH 很好用:

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class TestJPanels {

    private JLabel refPlusType;
    private JTextField addressLine1;

    protected void initUI() {
        final JFrame frame = new JFrame(TestJPanels.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel(new GridBagLayout());
        // Instantiate components and configure their corresponding GridBagConstraints attributes
        // refPlusType properties
        refPlusType = new JLabel("<html><h3>" + "Reference" + " - " + "Job Type" + " </h3><hr /></html>");
        GridBagConstraints refPlusTypeGC = new GridBagConstraints();
        refPlusTypeGC.gridwidth = GridBagConstraints.REMAINDER; // Number of colums occupied by component
        refPlusTypeGC.insets = new Insets(5, 10, 5, 10); // Specifies margin
        refPlusTypeGC.weightx = 1; // Required for anchor to work.
        refPlusTypeGC.anchor = GridBagConstraints.PAGE_START; // Position in container

        // addressLine1 properties
        addressLine1 = new JTextField(20);
        GridBagConstraints addressLine1GC = new GridBagConstraints();
        addressLine1GC.insets = new Insets(0, 10, 0, 10);
        addressLine1GC.fill = GridBagConstraints.HORIZONTAL; // Specifies component fill Horizontal space
        addressLine1GC.weightx = 1;
        addressLine1GC.weighty = 1;
        addressLine1GC.anchor = GridBagConstraints.NORTH;

        // Add components to this HALLogisticsDetailsPanel
        panel.add(refPlusType, refPlusTypeGC);
        panel.add(addressLine1, addressLine1GC);
        frame.add(panel);
        frame.setSize(600, 600);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestJPanels().initUI();
            }
        });
    }
}

通过从JLabel中删除weighty,锚点现在已经过时(即不起作用)。我看到这个方法是有效的,但是当我添加第三个组件并使用与addressLine1相同的格式时,它再次出现问题,以至于第三个组件漂浮在中间,而其他两个组件则在顶部。 - Rudi Kershaw
@RudiKershaw PAGE_START 相当于水平方向上的 NORTH,因此它将位于顶部居中。由于没有额外的垂直空间,它将“仅”在其“单元格”内水平居中组件。如果您希望所有组件都被推到顶部:要么您为最后一个组件使用 weighty > 0(并将其锚定为 NORTH),要么您添加一个具有 weighty > 0 的额外组件(透明)。为了得到完整的答案,请提供您想要的组件和布局草图的完整问题。 - Guillaume Polet

1
我所见过的最好的GridBagLayout“教程”是由Scott Stanchfield创建的。您可以在JavaOne 2001上他所做的PowerPoint演示中找到链接here
曾经有一篇包含相同信息的文章在线上,但现在似乎已被Oracle吞噬了。
请阅读所有关于为什么GBL不理想的警告。如果您决定使用它,Scott通过创建GUI的简单草图来确定所有约束条件,提供了一个很好的视觉教程。
Jim S.

很奇怪,第一次查阅时,我被推荐使用GBL作为最佳选择。甚至 Oracle 的网站也认同此观点。但现在我开始看到人们对它提出抱怨,并且个人也开始后悔选择了它。感觉好像白费了一天的工作时间。 - Rudi Kershaw
1
@RudiKershaw GBL可能是JRE提供的最灵活的LM,但学习它可能需要比其他LM多花费几分钟。然而,组合和嵌套更简单的“LayoutManager”也可以非常强大。如果您可以使用第三方库,您可以看看MigLayout,它非常流行,非常强大,学习起来也不太复杂。 - Guillaume Polet
+1,感谢分享链接 :-) 不过我需要等一会儿才能点赞,因为我今天的限制已经用完了。再次强调,我是GridBagLayout的忠实粉丝,无论别人怎么说它不好用,但是只要理解了它,就可以创造出惊人的效果 :-) - nIcE cOw

1
好的,我明白了。虽然我不太喜欢接受自己的答案,但是现在我来回答。归根结底,我想让所有的组件都能够正确地聚集在容器的顶部。将weighty属性分别添加到每个组件中意味着剩余空间将在它们之间分配(相对于它们的weighty属性),因此它们之间会有间隔。
答案似乎是:通过向GridBagLayout中的最低组件添加weighty属性,剩余的所有空间都被分配到该组件下方,从而将所有组件推到顶部。默认情况下,当基于权重分配剩余空间时,它被分配到组件的下方(至少在y轴上)。
以下是带有三个组件的新代码,以帮助演示:
    // Instantiate components and configure their corresponding GridBagConstraints attributes
    // refPlusType properties
    refPlusType = new JLabel("<html><h3>"+"Reference"+" - "+"Job Type"+" </h3><hr /></html>");
    refPlusTypeGC = new GridBagConstraints();
    refPlusTypeGC.gridx = 0; // Grid position 
    refPlusTypeGC.gridy = 0;
    refPlusTypeGC.gridwidth = 2; // Number of colums occupied by component
    refPlusTypeGC.insets = new Insets(5, 10, 5, 10); // Specifies margin

    // addressLine1 properties
    addressLine1 = new JTextField();
    addressLine1GC = new GridBagConstraints();
    addressLine1GC.gridx = 0; 
    addressLine1GC.gridy = 1;
    addressLine1GC.gridwidth = 2; 
    addressLine1GC.insets = new Insets(0, 10, 0, 10); 
    addressLine1GC.fill = GridBagConstraints.HORIZONTAL; // Specifies component fill Horizontal space

    // addressLine2 properties
    addressLine2 = new JTextField();
    addressLine2GC = new GridBagConstraints();
    addressLine2GC.gridx = 0; 
    addressLine2GC.gridy = 2;
    addressLine2GC.gridwidth = 2; 
    addressLine2GC.insets = new Insets(0, 10, 0, 10); 
    addressLine2GC.fill = GridBagConstraints.HORIZONTAL; // Specifies component fill Horizontal space 
    addressLine2GC.weighty = 1; // Required for anchor to work.
    addressLine2GC.anchor = GridBagConstraints.NORTH; // Position in container

    // Add components to this HALLogisticsDetailsPanel
    this.add(refPlusType, refPlusTypeGC);
    this.add(addressLine1, addressLine1GC);
    this.add(addressLine2, addressLine2GC);

1
weightx/weighty 表示您希望额外的水平/垂直空间如何分配。GridBagLayout 首先尝试将每个组件的首选大小分配给它们。如果有任何水平/垂直空间剩余,则它将对所有相应的权重进行求和,并使用比例权重分配额外的空间。 - Guillaume Polet
1
如果您采用一个基本的例子,其中有3个组件(c1、c2、c3)垂直地对齐在一起。容器的高度为100px,三个组件需要10、20和30px(总共60px,还有额外的40px垂直空间)。假设c1和c2声明了权重为1,而c3声明了权重为3(总权重为5)。c1和c2将获得额外空间的1/5-->8px,而c3将获得40px的3/5-->24px。最终,c1将有一个18px高的“单元格”,c2将有一个28px高的单元格,而c3将获得54px的高度(总共等于100px)。 - Guillaume Polet
谢谢Guillaume,现在我明白多了。我会编辑我的问题,以便简要概述最终产品的预期外观,如果您根据这些评论告诉我的内容修改您的答案并修改代码,那么我将接受您的答案。 - Rudi Kershaw

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