GridBagLayout 面板对齐

Posted

技术标签:

【中文标题】GridBagLayout 面板对齐【英文标题】:GridBagLayout panels alignment 【发布时间】:2013-01-23 05:03:12 【问题描述】:

我对 GridBag 布局管理器有一点问题。我正在尝试显示 9 个这样的面板:

为此,我像这样分隔网格:

对于面板 1 到 7 没有问题,它们会按照我的意愿显示。但问题始于面板S8S9。如您所见,S8S9 占据了一半的帧,但我不能让它像这样显示。 S8S4 的开头结束,S9S4 的末尾开始,我无法处理半个空格。

我想出的唯一方法是将S8S9 面板放在占用所有框架宽度的另一个面板中 - 但肯定必须有一种正确的方法来显示这两个面板而不将它们放在另一个面板中!

代码如下:

workzone.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.BOTH;
c.weightx = 0.5;
c.weighty = 0.5;
c.insets = new Insets(0,0,0,0);

//S1
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 2;
c.gridheight = 2;
workzone.add(S1, c);

//S2
c.gridx = 2;
c.gridy = 0;
c.gridwidth = 2;
c.gridheight = 1;
workzone.add(S2, c);

//S3
c.gridx = 2;
c.gridy = 1;
c.gridwidth = 2;
c.gridheight = 1;
workzone.add(S3, c);

//S4
c.gridx = 4;
c.gridy = 0;
c.gridwidth = 2;
c.gridheight = 2;
workzone.add(S4, c);

//S5
c.gridx = 7;
c.gridy = 0;
c.gridwidth = 1;
c.gridheight = 1;
workzone.add(S5, c);

//S6
c.gridx = 7;
c.gridy = 1;
c.gridwidth = 2;
c.gridheight = 1;
workzone.add(S6, c);

//S7
c.gridx = 8;
c.gridy = 0;
c.gridwidth = 2;
c.gridheight = 2;
workzone.add(S7, c);

//S8
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 5;
c.gridheigth = 1;
workzone.add(S8, c);

//S9
c.gridx = 6;
c.gridy = 2;
c.gridwidth = 5;
c.gridheight = 1;
workzone.add(S9, c);

欢迎提出任何想法和建议!

【问题讨论】:

【参考方案1】:

好问题。我花了一点时间来破解它,但我明白了。通常,我会将第 1-7 节放在顶部面板中,将第 8-9 节放在底部面板中,但我喜欢使用 GBL 来挑战 1 个面板。 [无聊]

问题是第 4 节(列索引 4 和 5)没有为 GBL 明确定义,因此第 8 节不知道要覆盖它的第五列(索引 4)多远,所以它就停止了在列索引 3 之后。

所以,我在构成第 4 部分的列中添加了 2 个零高度间隔,它起作用了。注释掉标有 SPACERS 的 2 行,看看我的意思:

编辑:添加了@SheridanVespo 建议的修复

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class GridBagDemo2 implements Runnable

  private Color[] colors = Color.BLACK, Color.BLUE, Color.CYAN, Color.GRAY,
                            Color.GREEN, Color.MAGENTA, Color.ORANGE,
                            Color.PINK, Color.RED, Color.YELLOW;

  private JPanel panel;
  private GridBagConstraints gbc;

  public static void main(String[] args)
  
    SwingUtilities.invokeLater(new GridBagDemo2());
  

  public void run()
  
    panel = new JPanel(new GridBagLayout());
    gbc = new GridBagConstraints();

    add(0,0, 2,2, "1");
    add(2,0, 2,1, "2");
    add(2,1, 2,1, "3");
    add(4,0, 2,2, "4");
    add(6,0, 2,1, "5");
    add(6,1, 2,1, "6");
    add(8,0, 2,2, "7");
    add(0,2, 5,1, "8");
    add(5,2, 5,1, "9");

    // SPACERS: define the 2 columns that is section "4"
    add(4,3, 1,1, "");
    add(5,3, 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(int x, int y, int colspan, int rowspan, String name)
  
    gbc.gridx = x;
    gbc.gridy = y;
    gbc.gridwidth = colspan;
    gbc.gridheight = rowspan;
    gbc.weightx = .1;
    gbc.weighty = .1;
    gbc.anchor = GridBagConstraints.CENTER;
    gbc.fill = GridBagConstraints.BOTH;

    // using another panel for illustrative purposes only
    JPanel p = new JPanel();

    if (!name.equals(""))
    
      gbc.weightx = 1;                          // @SheridanVespo fix
      int index = Integer.parseInt(name);
      JLabel label = new JLabel("Panel " + name);
      p.add(label);
      p.setBackground(colors[index]);
      panel.add(p, gbc);
    
    else
    
      gbc.weightx = 0.5;                        // @SheridanVespo fix
      gbc.weighty = 0;  // don't allow the spacer to grow 
      gbc.fill = GridBagConstraints.NONE;
      panel.add(Box.createHorizontalGlue(), gbc);
    
  

【讨论】:

@splungebob :我喜欢这种方法,但仍然对你是如何管理它的 :-) 摸不着头脑。对HorizontalGlue 东西知之甚少,所以在阅读关于这个东西的教程时可能会拉扯我的头发:-) +1 为你的答案,这确实迫使我删除我的:-) @GagandeepBali:我鼓励你恢复你的答案,因为它为未来的访问者提供了一个有用的替代方案,可以避免第 4 节提到的 here 的异常调整大小行为。 @splungebob 我找到了修复代码的方法:将gbc.weightx = a 用于面板,gbc.weightx = b 用于带有a > b > 0 的胶水。 (您使用了a = b)这样所有列都以相同的方式调整大小。 @trashgod 无需恢复,可修复。 @SheridanVespo 您的修复似乎有效,因此我将其添加到答案中。谢谢。【参考方案2】:

接受的answer 很有吸引力,但它会导致第 4 部分在调整框架大小时比侧面板更快地加宽。此变体将面板 8 和 9 放置在 BoxLayout 的单独子面板中。

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

/** @see https://***.com/q/14755487/261156 */
public class GridBagDemo implements Runnable 

    private JPanel panel;

    public static void main(String[] args) 
        SwingUtilities.invokeLater(new GridBagDemo());
    

    @Override
    public void run() 
        JFrame frame = new JFrame("GridBag");
        frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
        panel = new JPanel(new GridBagLayout());
        add(1, 0, 0, 1, 2);
        add(2, 1, 0, 1, 1);
        add(3, 1, 1, 1, 1);
        add(4, 2, 0, 1, 2);
        add(5, 3, 0, 1, 1);
        add(6, 3, 1, 1, 1);
        add(7, 4, 0, 1, 2);
        frame.add(panel);
        panel = new JPanel(new GridBagLayout());
        add(8, 0, 0, 1, 1);
        add(9, 1, 0, 1, 1);
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    

    private void add(int i, int x, int y, int w, int h) 
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = x;
        gbc.gridy = y;
        gbc.gridwidth = w;
        gbc.gridheight = h;
        gbc.weightx = .1;
        gbc.weighty = .1;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.fill = GridBagConstraints.BOTH;
        JPanel p = new JPanel();
        p.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        p.add(new JLabel("Panel " + i));
        p.setBackground(Color.getHSBColor((i - 1) / 9f, 0.75f, 0.95f));
        panel.add(p, gbc);
    

【讨论】:

这又是一个使用BoxLayout 的好例子。仍在尝试答案并阅读教程以了解更多信息 :-) 接受您的建议 :-) 这里也一样,感谢您对各种方法的贡献。设计师经常指定静态布局;用户经常要求调整大小时的特定动态行为。内容很重要:footerPanelGridLayout 可能最适合状态显示;我的可能适合桌子等。【参考方案3】:

我尝试使用BorderLayout 来检查它是如何工作的。但只是在这里发布.. :) 这个过程在彼此内部使用多个面板。如果这个例子很舒服,你可以试试这个方法。

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;


public class BorderAndGridBag 
    public static void main(String[] args) 
        Runnable r = new Runnable() 

            @Override
            public void run() 
                new GridWithBorder().createUI();
            
        ;

        EventQueue.invokeLater(r);
    


class GridWithBorder 
    public void createUI() 
        JFrame frame = new JFrame();

        JPanel motherPanel = new JPanel(new BorderLayout());

        JPanel topPanel = new  JPanel();
        topPanel.setBorder(LineBorder.createBlackLineBorder());

        JPanel bottomPanel = new JPanel(new BorderLayout());
        bottomPanel.setBorder(LineBorder.createBlackLineBorder());

        JPanel topLeftPanel = new JPanel();
        topLeftPanel.setBorder(LineBorder.createBlackLineBorder());

        JPanel topRightPanel = new JPanel();
        topRightPanel.setBorder(LineBorder.createBlackLineBorder());

        JPanel topMiddlePanel = new JPanel();
        topMiddlePanel.add(new JLabel("Top Middle"));
        topMiddlePanel.setBorder(LineBorder.createBlackLineBorder());

        JPanel bottomLeftPanel = new JPanel();
        bottomLeftPanel.add(new JLabel("Bottom Left"));
        bottomLeftPanel.setBorder(LineBorder.createBlackLineBorder());

        JPanel bottomRightPanel = new JPanel();
        bottomRightPanel.add(new JLabel("Bottom Right"));
        bottomRightPanel.setBorder(LineBorder.createBlackLineBorder());

        JPanel topLeftLeft = new JPanel();
        topLeftLeft.add(new JLabel("Top Left"));
        topLeftLeft.setBorder(LineBorder.createBlackLineBorder());


        JPanel topLeftRight = new JPanel(new BorderLayout());

        JPanel topLeftRightTop = new JPanel();
        topLeftRightTop.add(new JLabel("Top Left's Right Top"));
        topLeftRight.setBorder(LineBorder.createBlackLineBorder());

        JPanel topLeftRightBottom = new JPanel();
        topLeftRightBottom.add(new JLabel("Top Left's Right Bottom"));

        JPanel topRightLeft = new JPanel(new BorderLayout());
        topRightLeft.setBorder(LineBorder.createBlackLineBorder());

        JPanel topRightRight = new JPanel();
        topRightRight.add(new JLabel("Top Right Right"));
        topRightRight.setBorder(LineBorder.createBlackLineBorder());

        JPanel topRightLeftTop = new JPanel();
        topRightLeftTop.add(new JLabel("Top Right Left Top"));

        JPanel topRightLeftBottom = new JPanel();
        topRightLeftBottom.add(new JLabel("Top Right Left Bottom"));

        topLeftPanel.add(topLeftLeft, BorderLayout.WEST);

        // Top panel sub alignment.
        topLeftPanel.add(topLeftRight, BorderLayout.EAST);
        topLeftRight.add(topLeftRightTop, BorderLayout.NORTH);
        topLeftRight.add(topLeftRightBottom, BorderLayout.CENTER);


        topRightLeft.add(topRightLeftTop, BorderLayout.NORTH);
        topRightLeft.add(topRightLeftBottom, BorderLayout.SOUTH);
        topRightPanel.add(topRightLeft, BorderLayout.WEST);
        topRightPanel.add(topRightRight, BorderLayout.EAST);

        // Top Panel main alignment.
        topPanel.add(topLeftPanel, BorderLayout.WEST);
        topPanel.add(topMiddlePanel, BorderLayout.CENTER);
        topPanel.add(topRightPanel, BorderLayout.EAST);

        // Bottom Panel main alignment.
        bottomPanel.add(bottomLeftPanel, BorderLayout.WEST);
        bottomPanel.add(bottomRightPanel, BorderLayout.EAST);

        motherPanel.add(topPanel, BorderLayout.NORTH);
        motherPanel.add(bottomPanel, BorderLayout.CENTER);

        frame.add(motherPanel);
        frame.pack();
        frame.setTitle("Layout Manager");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    

【讨论】:

【参考方案4】:

对于最后两个JPanel,我建议您简单地将它们添加到带有GridLayout 的新JPanel 并将此JPanelGridLayout 设置为具有@987654328 的JPanel @。请看一下代码示例,它实际上产生了与您期望的相同的输出:

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

/**
 * Created with IntelliJ IDEA.
 * User: Gagandeep Bali
 * Date: 2/7/13
 * Time: 10:34 PM
 * To change this template use File | Settings | File Templates.
 */
public class GridBagExample

    private JPanel contentPane, footerPanel;
    private JPanel s1, s2, s3, s4, s5, s6, s7, s8, s9;

    private void displayGUI()
    
        JFrame frame = new JFrame("GridBagLayout Example");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        contentPane = new JPanel();
        contentPane.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        /*
         * Constraints for S1 JPanel.
         */
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridwidth = 1;
        gbc.gridheight = 2;
        gbc.weightx = 0.2;
        gbc.weighty = 0.8;
        s1 = new JPanel(new GridBagLayout());
        s1.setOpaque(true);
        s1.setBackground(Color.BLUE);
        s1.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 5));
        JLabel s1Label = new JLabel("S1", JLabel.CENTER);
        s1.add(s1Label);
        contentPane.add(s1, gbc);

        /*
         * Constraints for S2 JPanel.
         */
        gbc.weighty = 0.4;
        gbc.gridx = 1;
        gbc.gridheight = 1;
        s2 = new JPanel(new GridBagLayout());
        s2.setOpaque(true);
        s2.setBackground(Color.GREEN);
        s2.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 5));
        JLabel s2Label = new JLabel("S2", JLabel.CENTER);
        s2.add(s2Label);
        contentPane.add(s2, gbc);

        /*
         * Constraints for S3 JPanel.
         */
        gbc.gridy = 1;
        s3 = new JPanel(new GridBagLayout());
        s3.setOpaque(true);
        s3.setBackground(Color.CYAN);
        s3.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 5));
        JLabel s3Label = new JLabel("S3", JLabel.CENTER);
        s3.add(s3Label);
        contentPane.add(s3, gbc);

        /*
         * Constraints for S4 JPanel.
         */
        gbc.weighty = 0.8;
        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.gridheight = 2;
        s4 = new JPanel(new GridBagLayout());
        s4.setOpaque(true);
        s4.setBackground(Color.WHITE);
        s4.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 5));
        JLabel s4Label = new JLabel("S4", JLabel.CENTER);
        s4.add(s4Label);
        contentPane.add(s4, gbc);

        /*
         * Constraints for S5 JPanel.
         */
        gbc.weighty = 0.4;
        gbc.gridx = 3;
        gbc.gridheight = 1;
        s5 = new JPanel(new GridBagLayout());
        s5.setOpaque(true);
        s5.setBackground(Color.RED);
        s5.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 5));
        JLabel s5Label = new JLabel("S5", JLabel.CENTER);
        s5.add(s5Label);
        contentPane.add(s5, gbc);

        /*
         * Constraints for S6 JPanel.
         */
        gbc.gridy = 1;
        s6 = new JPanel(new GridBagLayout());
        s6.setOpaque(true);
        s6.setBackground(Color.MAGENTA);
        s6.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 5));
        JLabel s6Label = new JLabel("S6", JLabel.CENTER);
        s6.add(s6Label);
        contentPane.add(s6, gbc);

        /*
         * Constraints for S7 JPanel.
         */
        gbc.gridheight = 2;
        gbc.weighty = 0.8;
        gbc.gridx = 4;
        gbc.gridy = 0;
        s7 = new JPanel(new GridBagLayout());
        s7.setOpaque(true);
        s7.setBackground(Color.ORANGE);
        s7.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 5));
        JLabel s7Label = new JLabel("S7", JLabel.CENTER);
        s7.add(s7Label);
        contentPane.add(s7, gbc);

        footerPanel = new JPanel();
        footerPanel.setLayout(new GridLayout(1, 2, 5, 5));

        s8 = new JPanel(new GridBagLayout());
        s8.setOpaque(true);
        s8.setBackground(Color.PINK);
        s8.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 5));
        JLabel s8Label = new JLabel("S8", JLabel.CENTER);
        s8.add(s8Label);
        footerPanel.add(s8);

        s9 = new JPanel(new GridBagLayout());
        s9.setOpaque(true);
        s9.setBackground(Color.YELLOW);
        s9.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 5));
        JLabel s9Label = new JLabel("S9", JLabel.CENTER);
        s9.add(s9Label);
        footerPanel.add(s9, gbc);

        /*
         * Constraints for Footer JPanel.
         */
        gbc.gridheight = 1;
        gbc.gridwidth = 5;
        gbc.weightx = 1.0;
        gbc.weighty = 0.2;
        gbc.gridx = 0;
        gbc.gridy = 2;
        contentPane.add(footerPanel, gbc);

        frame.setContentPane(contentPane);
        frame.pack();
        //frame.setSize(500, 500);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    

    public static void main(String... args)
    
        EventQueue.invokeLater(new Runnable()
        
            @Override
            public void run()
            
                new GridBagExample().displayGUI();
            
        );
    

这是上面代码的输出:

【讨论】:

是的,我已经尝试过了,这是我的 B 计划。^^ 但是要管理每个面板上的事件,使用 GBL 更容易。但是感谢您提供完整的答案! @Dar-Jee : 非常欢迎你并保持微笑 :-) 仍然不清楚这些事件!这些事件是否与具有GridBagLaqyoutJPanel 或它上面的组件相关。因为如果答案晚了,我真的不认为这会出现任何问题。 @Dar-Jee 但是要管理每个面板上的事件,使用 GBL 会更容易。你在说什么事件?【参考方案5】:

对于 S9 组件,您的代码是

//S9
c.gridx = 6;
c.gridy = 2;
c.gridwidth = 5;
c.gridheight = 1;
workzone.add(S9, c);

由于坐标系从0而不是1开始,我建议代码是

//S9
c.gridx = 5; // I changed this
c.gridy = 2;
c.gridwidth = 5;
c.gridheight = 1;
workzone.add(S9, c);

【讨论】:

在此更改之后,S9 面板在 S8 之后开始,但与 S4 在同一点(S8 现在占用 4 个单元格,S9 占用 6 个单元格)。 ://【参考方案6】:

通常,我以 Y、X 位置顺序创建和添加 GridBagLayout 的组件。我不知道这是否是必需的,但它使我更容易诊断问题。

这是我为您的网格设计的。

Component   xPosition   yPosition   xWidth   yHeight
---------   ---------   ---------   ------   -------
S1              0           0          2        2
S2              2           0          2        1
S4              4           0          2        2
S5              6           0          2        1
S7              8           0          2        2
S8              0           2          5        1
S3              2           2          2        1
S9              5           2          5        1
S6              6           2          2        1

【讨论】:

【参考方案7】:

我从来都不是 GridBagLayout 的忠实粉丝。所以对我来说,我会将您的 GUI 分解为多个面板,并且可能会使用多个 GridLayout 来实现您想要的。比如:

JPanel top = new JPanel( new GridLayout(0, 5) );
top.add(s1);
JPanel s23 = new JPanel( new GridLayout(2, 0) );
s23.add(s2);
s23.add(s3);
top.add(s23);
...

JPanel bottom = new JPanel( new GridLayout(0, 2) );
bottom.add(s8);
bottom.add(s9);

JPanel main = new JPanel( appropriate layout manager );
main.add(top);
main.add(bottom);

【讨论】:

以上是关于GridBagLayout 面板对齐的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 GridBagLayout 在 JPanel 中对齐组件中心?

如何使用Java AWT / Swing垂直对齐面板

如何使用 Java AWT/Swing 垂直对齐面板

与 GridBagLayout 右对齐

java GridBagLayout布局,下面的代码怎么修改让一个按钮占两行一列,

如何在 GridBagLayout 中垂直对齐不同大小的按钮?