Java GridBagLayout无法工作

12

我正在尝试使用GridBagLayout,但是得到的结果与我的预期不符,而且我在这段代码中也找不到错误:

public class GridBagEx1 extends JPanel {

    private static final long serialVersionUID = 1L;

    protected void makebutton(String name, GridBagLayout gridbag, GridBagConstraints c) {
        JButton button = new JButton(name);
        gridbag.setConstraints(button, c);
        add(button);
    }

    public void init() {
        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints c = new GridBagConstraints();
        setLayout(gridbag);

        c.fill = BOTH;

        c.weightx = 1.0;
        c.weighty = 1.0;

        c.anchor = CENTER;

        c.insets.top = 5;
        c.insets.bottom = 5;
        c.insets.left = 5;
        c.insets.right = 5;

        c.gridx = 0;
        c.gridy = 0;
        c.gridheight = 1;
        c.gridwidth = 2;
        makebutton("Button1", gridbag, c);      

        c.gridx = 2;
        c.gridy = 0;
        c.gridheight = 1;
        c.gridwidth = 1;
        makebutton("Button2", gridbag, c);

        c.gridx = 3;
        c.gridy = 0;
        c.gridheight = 2;
        c.gridwidth = 2;
        makebutton("Button3", gridbag, c);

        c.gridx = 0;
        c.gridy = 1;
        c.gridheight = 1;
        c.gridwidth = 1;
        makebutton("Button4", gridbag, c);

        c.gridx = 1;
        c.gridy = 1;
        c.gridheight = 1;
        c.gridwidth = 2;
        makebutton("Button5", gridbag, c);

        c.gridx = 0;
        c.gridy = 2;
        c.gridheight = 1;
        c.gridwidth = 1;
        makebutton("Button6", gridbag, c);

        c.gridx = 1;
        c.gridy = 2;
        c.gridheight = 1;
        c.gridwidth = 2;
        makebutton("Button7", gridbag, c);

        c.gridx = 3;
        c.gridy = 2;
        c.gridheight = 1;
        c.gridwidth = 1;
        makebutton("Button8", gridbag, c);

        c.gridx = 4;
        c.gridy = 2;
        c.gridheight = 1;
        c.gridwidth = 1;
        makebutton("Button9", gridbag, c);
    }

    public static void main(String args[]) {
        JFrame frame = new JFrame();
        GridBagEx1 ex1 = new GridBagEx1();

        ex1.init();

        frame.add(ex1);
        frame.pack();
        frame.setVisible(true);
    }
}

这张图片展示了我需要的内容:

程序员喜欢绘画

黄色是按钮名称,红色是行和列。

这是实际发生的情况: 这里有什么问题?

有人能解释一下我的代码出了什么问题吗?


6
我还不能解释这个问题,但我必须声明你的问题表述得非常好,谢谢你并点赞+1。 - Hovercraft Full Of Eels
c.fill = BOTH; 应改为 c.fill = GridBagConstraints.BOTH; ,同样地,c.anchor = CENTER; 也需要修改为能够编译的代码。 - user1803551
2
@user1803551 如果你使用 import static java.awt.GridBagConstraints.*; 就不需要了 :-) - Gerold Broser
我能向您介绍一下GroupLayout吗? :) - user1803551
不是MigLayout。但是要感谢Boann和他的回答。1+ - Hovercraft Full Of Eels
显示剩余6条评论
2个回答

8
问题在于没有任何东西能够说服第二个网格列(gridx=1)具有任何宽度,因为没有组件需要仅适合于第二列。第二列因此宽度为0,因此尽管Button1跨越了前两列,但它看起来并非如此,因为其所有宽度需求都满足于第一列;而尽管Button5和Button7跨越了第二和第三列,但它们所有的宽度需求都满足于第三列。
要解决这个问题,您必须说服应该更宽(1、5、7)的按钮占用更多的空间。在这里,我通过设置 c.ipadx = 35; 向这些按钮添加填充。(我还删除了 weightx = 1.0 约束。由于某些原因我不太理解,当这个约束保留时它不起作用。)
来源:
public void init() {
    GridBagLayout gridbag = new GridBagLayout();
    GridBagConstraints c = new GridBagConstraints();
    setLayout(gridbag);

    c.fill = c.BOTH;

    //c.weightx = 1.0;
    //c.weighty = 1.0;

    c.anchor = c.CENTER;

    c.insets.top = 5;
    c.insets.bottom = 5;
    c.insets.left = 5;
    c.insets.right = 5;

    c.gridx = 0;
    c.gridy = 0;
    c.gridheight = 1;
    c.gridwidth = 2;
    c.ipadx = 35;
    makebutton("Button1", gridbag, c);

    c.gridx = 2;
    c.gridy = 0;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.ipadx = 0;
    makebutton("Button2", gridbag, c);

    c.gridx = 3;
    c.gridy = 0;
    c.gridheight = 2;
    c.gridwidth = 2;
    c.ipadx = 0;
    makebutton("Button3", gridbag, c);

    c.gridx = 0;
    c.gridy = 1;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.ipadx = 0;
    makebutton("Button4", gridbag, c);

    c.gridx = 1;
    c.gridy = 1;
    c.gridheight = 1;
    c.gridwidth = 2;
    c.ipadx = 35;
    makebutton("Button5", gridbag, c);

    c.gridx = 0;
    c.gridy = 2;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.ipadx = 0;
    makebutton("Button6", gridbag, c);

    c.gridx = 1;
    c.gridy = 2;
    c.gridheight = 1;
    c.gridwidth = 2;
    c.ipadx = 35;
    makebutton("Button7", gridbag, c);

    c.gridx = 3;
    c.gridy = 2;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.ipadx = 0;
    makebutton("Button8", gridbag, c);

    c.gridx = 4;
    c.gridy = 2;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.ipadx = 0;
    makebutton("Button9", gridbag, c);
}

编辑:评论中指出,上述方法不适用,因为它防止布局被动态调整大小。要使布局扩展以填充其容器的大小,需要使用weightxweighty约束条件,但这样第二列就不会获得任何宽度。

这里尝试一种替代解决方案。这是一个不太好的技巧,它在第二列底部插入一个无形组件,以强制第二列具有宽度:

    c.gridx = 1;
    c.gridy = 3;
    c.gridheight = 1;
    c.gridwidth = 1;
    c.insets.set(0, 0, 0, 0);
    c.weighty = 0;
    add(Box.createRigidArea(new Dimension(50, 0)), c);

当窗口被调整大小时,这种方法处理得相当好,因为尽管组件具有固定的初始大小,GridBagLayout会与其他组件成比例地缩放。不过,它仍然不完美。也许有更好的解决方案,但我找不到。


@FilipB.Vondrášek 我认为_这个_特定的案例和一个具体(相当复杂)的布局管理器并不总结和证明Swing是一种可憎的东西。当然,Swing有其优缺点,但它不像是一个秘密,每个人都知道。 - icza
@FilipB.Vondrášek 如果只有一个非常糟糕的替代方案就好了。 - Boann
JavaFX怎么样?我从来没有用过。 - Filip Vondrášek
@Boann 移除了 weighty 和 x 属性后,按钮不会自适应大小。如果你重新添加它们,这段代码将无法正常工作! - Emax
@Boann 另外一件事,按钮本身没有尺寸,我希望 GridBagLayout 根据 JPanel 给它们分配一个基础尺寸! - Emax

2

我使用JGoodies FormLayout成功设计出所需的布局,而且支持动态缩放,没有任何hack。

import java.awt.Component;

import javax.swing.JButton;
import javax.swing.JPanel;

import com.jgoodies.forms.factories.FormFactory;
import com.jgoodies.forms.layout.ColumnSpec;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;

public class FormLayoutPanel extends JPanel
    {
    public FormLayoutPanel()
        {
        setAlignmentY( Component.BOTTOM_ALIGNMENT );
        setAlignmentX( Component.RIGHT_ALIGNMENT );
        setLayout( new FormLayout( new ColumnSpec[] {
            ColumnSpec.decode( "41px:grow" ),
            FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            ColumnSpec.decode( "25px:grow" ),
            FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            ColumnSpec.decode( "41px:grow" ),
            FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            ColumnSpec.decode( "41px:grow" ),
            FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            ColumnSpec.decode( "41px:grow" ), },
            new RowSpec[] {
                RowSpec.decode( "25px:grow" ),
                FormFactory.LINE_GAP_ROWSPEC,
                RowSpec.decode( "25px:grow" ),
                FormFactory.LINE_GAP_ROWSPEC,
                RowSpec.decode( "25px:grow" ), } ) );

        JButton button1 = new JButton( "1" );
        add( button1, "1, 1, 3, 1, fill, fill" );
        JButton button2 = new JButton( "2" );
        add( button2, "5, 1, fill, fill" );
        JButton button3 = new JButton( "3" );
        add( button3, "7, 1, 3, 3, fill, fill" );
        JButton button4 = new JButton( "4" );
        add( button4, "1, 3, fill, fill" );
        JButton button5 = new JButton( "5" );
        add( button5, "3, 3, 3, 1, fill, fill" );
        JButton button6 = new JButton( "6" );
        add( button6, "1, 5, fill, fill" );
        JButton button7 = new JButton( "7" );
        add( button7, "3, 5, 3, 1, fill, fill" );
        JButton button8 = new JButton( "8" );
        add( button8, "7, 5, fill, fill" );
        JButton button9 = new JButton( "9" );
        add( button9, "9, 5, fill, fill" );
        }
    }

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