【问题标题】:GridBagLayouts in GridLayoutGridLayout 中的 GridBagLayout
【发布时间】:2023-03-06 05:45:02
【问题描述】:

尝试在 Swing 中构建这个 GUI:

在我的 MainFrame 中,我设置了一个这样的 GridLayout 来实现 1 行 2 列:

setLayout(new GridLayout(1, 2));

在左栏中,我认为我需要一个 GridBagLayout,就像在右栏中一样。普通 GridLayout 不再起作用,因为我想要每行的不同大小。对于左列,我尝试了这个:

GridBagConstraints gbc = new GridBagConstraints();

    mapPanel = new MapPanel(map);
    gbc.fill = GridBagConstraints.BOTH;
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.gridheight = 10;
    add(mapPanel, gbc);

    controlPanel = new JPanel();
    controlPanel.add(new JButton("Test"));
    controlPanel.add(new JButton("Test 2"));
    controlPanel.add(new JButton("Test 3"));
    controlPanel.add(new JButton("Test 4"));
    gbc.fill = GridBagConstraints.BOTH;
    gbc.gridx = 0;
    gbc.gridy = 1;
    gbc.gridheight = 1;
    add(controlPanel, gbc);

    logPanel = new LogPanel();
    gbc.fill = GridBagConstraints.BOTH;
    gbc.gridx = 0;
    gbc.gridy = 2;
    gbc.gridheight = GridBagConstraints.REMAINDER;
    add(logPanel, gbc);

但是,这将导致左侧列中的所有内容“打包在一起”。它不会扩展到列的 100% 高度和 50% 宽度。如何实现如图所示的 GUI?

谢谢!

【问题讨论】:

  • 您是否对您布局的组件中的setPreferredSize(Dimension) 进行了实验?此属性与布局管理器如何呈现结果密切相关。
  • @AndrewThompson 我同意最好不要调整组件的首选大小,但布局管理器倾向于使用它们,即使不是由“我们”设置。我的评论指向了那个方向......希望我的回答好一点。
  • “我同意最好不要调整组件的首选大小,” 该线程中的建议并没有说不要“调整”它们,只是不要调用 set. 如有必要,覆盖默认方法,但这里没有必要。空边框可以填充标签,文本字段具有 setColumns(int) 方法来建议大小。 试图猜测组件所需的大小将导致 GUI 脆弱。
  • @AndrewThompson 的“tweak”实际上是指“set”,一开始可能会更好。

标签: swing user-interface layout-manager grid-layout gridbaglayout


【解决方案1】:

仅使用 GridBagLayout 就足够了。

通过设置gbc.gridheight = 10,您告诉GridBag 为组件使用10 行。 (类似于 HTML 中的 rowspan。)然而,这并没有说明组件的实际高度,因为行没有固定的高度。因此,当您仅使用单个列时,此约束不会产生任何影响。约束的名称在恕我直言令人困惑。

使用GridBagConstraints.weightxGridBagConstraints.weighty 指定额外空间的位置。请参阅How to Use GridBagLayout 了解更多信息。

结合组件的首选尺寸,您将能够获得一个面板,该面板将在面板较小时显示您的组件,并在面板“太大”时分配额外空间。

不过,正如 Andrew Thompson 指出的那样,使用 setPreferredSize() 并不是一个很好的方法。通常,组件已经具有它们的首选尺寸,就像构造的一样。随便玩一下GridBagConstraints,看看会发生什么。

这最终可能是一个更好看的解决方案。

【讨论】:

    【解决方案2】:

    看看JNodeLayout。 RectNode 正是您所需要的。

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Container;
    import java.awt.geom.Rectangle2D;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.border.EmptyBorder;
    import javax.swing.border.LineBorder;
    
    import com.smartg.swing.layout.JNodeLayout;
    import com.smartg.swing.layout.LayoutNode.RectNode;
    
    public class RectNodeDemo {
    
        public static void main(String[] args) {
    
            String rootName = "root";
            RectNode root = new RectNode(rootName);
            JNodeLayout layout = new JNodeLayout(root);
            layout.setHgap(1);
            layout.setVgap(1);
    
    
            JPanel target = new JPanel();
            target.setBorder(new EmptyBorder(10, 10, 10, 10));
    
            target.setLayout(layout);
    
            addPanel(target, root, new Rectangle2D.Double(0, 0, .5, .5));
            addPanel(target, root, new Rectangle2D.Double(0, .5, .5, .1));
            addPanel(target, root, new Rectangle2D.Double(0, .6, .5, .4));  
    
            addPanel(target, root, new Rectangle2D.Double(.5, 0, .5, .9));
            addPanel(target, root, new Rectangle2D.Double(.5, .9, .5, .1));
    
            layout.syncNodes();
    
            JFrame frame = new JFrame();
    
            Container contentPane = frame.getContentPane();
            contentPane.setLayout(new BorderLayout());
            contentPane.add(target, BorderLayout.CENTER);
            frame.pack();
            frame.setVisible(true);
        }
    
        static void addPanel(JPanel target, RectNode node, Rectangle2D r) {
            JPanel p = new JPanel();
            target.add(p);
            p.setBorder(new LineBorder(Color.BLACK, 1));
            node.add(p, r);
        }
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用Relative Layout。此布局允许您指定每个组件的相对大小。

      要在左侧创建面板,代码如下:

      RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
      rl.setFill( true );
      JPanel left = new JPanel( rl );
      left.add(panel1, new Float(50));
      left.add(panel2, new Float(10));
      left.add(panel3, new Float(40));
      

      【讨论】: