寻找GridBagLayout组件创建的一般方法

时间:2014-01-09 02:49:43

标签: java swing layout-manager gridbaglayout

我正在设计一个包含20个左右组件的GUI:10个标签,4个文本字段,4个按钮和2个文本区域。使用GridBagLayout似乎是一个好主意。但是,对于每个组件,本书需要执行所有实例变量(即,不重用),添加组件的一般方法似乎是必须的。我真的认为这可行:

(注意:HORIZ是GridBagConstraints.HORIZONTAL的缩写;       CENTER是GridBagConstraints.CENTER的缩写。)

public static void addComponent(Container f,      Component c, 
                                  int     x,        int   y, 
                                  int     w,        int   h, 
                                  int     ipadx,    int   ipady, 
                                  float   wtx,      float wty,
                                  int fill, int anchor, Insets insets){


  GridBagConstraints gbc = new GridBagConstraints();

  gbc.gridx = x;    gbc.gridy = y;      
  gbc.gridwidth = w;    gbc.gridheight = h;     
  gbc.fill = fill; 
  gbc.ipadx = ipadx;    gbc.ipady = ipady;  
  gbc.insets = insets;  gbc.anchor = anchor; 
  gbc.weightx = wtx;    gbc.weighty = wty;

  f.add(c,gbc);
}

我这样称呼它:

    Insets insets = new Insets(0,0,0,0);
    JFrame frame = new JFrame();
    label = new JLabel("Blablablah");   
    addComponent(frame, label, 0,0, 1,1, 0,0, 0.5f,0, HORIZ, CENTER, insets);

但我在f.add(c.gbc)收到消息“无法添加到布局:约束必须是字符串(或null)”。

我想我理解错误:frame在调用GridBagConstraints之前没有addComponent,而gbc在方法的第一行没有f属于参数Container(或其他什么?)。

所以我稍微修改了方法签名,省略了public static void addComponent( Component c, int x, int y, ... (rest unchanged)

frame.add(c, gbc);

我修改了问题行:

frame

所以当我宁愿将它作为参数传递时,我正在使用全局变量frame

两个问题:

(1)有没有办法最低限度地修改我的代码以启用addComponentaddComponent

(2)有什么理由要这样做吗?我想这相当于问,你会做什么?


P.S。这是对修改后的frame的调用,匆匆一起抛出,以获得我想要的前几行的一些外观。此刻的间距令人沮丧 - 我需要用插图,ipads,填充来实现 - 但它实际上是可用的。 (GUI的新名称为private static void createAndShowGUI() { GUI = new JFrame(); GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); gbl = new GridBagLayout(); GUI.setLayout(gbl); addComponent(lblRootNode, 0,0, 1,1, 0,0, 0.5f,0, HORIZONTAL, CENTER, new Insets(0,0,0,0)); addComponent(txtRootNode, 1,0, 5,1, 60,0, 0.5f,0, HORIZONTAL, CENTER, new Insets(0,0,0,0)); addComponent(btnBrowse, 6,0, 1,1, 0,0, 0.5f,0, HORIZONTAL, CENTER, new Insets(0,0,0,0)); addComponent(lblFilenamePat, 0,1, 2,1, 0,0, 0.5f,0, HORIZONTAL, EAST, new Insets(0,0,0,0)); addComponent(txtFilenamePat, 2,1, 4,1, 0,0, 0.5f,0, HORIZONTAL, LINE_END, new Insets(0,0,0,0)); addComponent(lblDates, 0,2, 2,1, 0,0, 0.5f,0, HORIZONTAL, CENTER, new Insets(0,0,0,0)); addComponent(lblSizes, 2,2, 2,1, 0,0, 0.5f,0, HORIZONTAL, CENTER, new Insets(0,0,0,0)); 。)

{{1}}

...

4 个答案:

答案 0 :(得分:3)

我使用GridBagLyout很多,但和我之前的很多其他人一样,我很快发现它可能非常冗长。网上有很多关于用户如何编写实用程序方法和/或类来帮助他们生成GBL代码的例子。我会告诉你我做了什么。

1)首先,我创建了2个枚举,它们是锚点填充 GridBagConstraints字段的包装器。我更喜欢enums与int的类型检查,它还允许我编写更简洁的代码(稍后你会看到)。是的,我仍然使用较旧的“方向”值为Anchor。我永远不会习惯PAGE_START之类的首选值。使用你喜欢的任何东西。

Anchor.java:

package gbl;

import java.awt.*;

/**
 * Convenience enum that aliases out all possible values for the
 * GridBagConstraints anchor property.
 */
public enum Anchor
{
  NORTH(GridBagConstraints.NORTH),
  SOUTH(GridBagConstraints.SOUTH),
  EAST(GridBagConstraints.EAST),
  WEST(GridBagConstraints.WEST),
  NORTHEAST(GridBagConstraints.NORTHEAST),
  NORTHWEST(GridBagConstraints.NORTHWEST),
  SOUTHEAST(GridBagConstraints.SOUTHEAST),
  SOUTHWEST(GridBagConstraints.SOUTHWEST),
  CENTER(GridBagConstraints.CENTER);

  private int constraint;

  private Anchor(int gbConstraint)
  {
    constraint = gbConstraint;
  }

  public int getConstraint()
  {
    return constraint;
  }
}

Fill.java:

package gbl;

import java.awt.*;

/**
 * Convenience enum that aliases out all possible values for the
 * GridBagConstraints fill property.
 */
public enum Fill
{
  NONE(GridBagConstraints.NONE),
  HORIZONTAL(GridBagConstraints.HORIZONTAL),
  VERTICAL(GridBagConstraints.VERTICAL),
  BOTH(GridBagConstraints.BOTH);

  private int constraint;

  private Fill(int gbConstraint)
  {
    constraint = gbConstraint;
  }

  public int getConstraint()
  {
    return constraint;
  }
}

2)然后,我创建了一个GridBagConstraints的子类,它允许我在需要时“链接”属性,同时使用常见的默认值:

GBConstraints.java:

package gbl;

import java.awt.*;

/**
 * Convenience class to simplify the creation of a GridBagConstraints object.
 */
public class GBConstraints extends GridBagConstraints
{
  public GBConstraints(int gridX, int gridY)
  {
    super();

    this.gridx = gridX;
    this.gridy = gridY;

    this.gridwidth = 1;
    this.gridheight = 1;
    this.weightx = 0;
    this.weighty = 0;
    this.anchor = NORTHWEST;              // old default was CENTER
    this.fill = NONE;
    this.insets = new Insets(1,2,1,2);    // old default was (0,0,0,0)
    this.ipadx = 1;                       // old default was 0
    this.ipady = 1;                       // old default was 0
  }

  public GBConstraints anchor(Anchor anchor)
  {
    this.anchor = anchor.getConstraint();
    return this;
  }

  public GBConstraints fill(Fill fill)
  {
    this.fill = fill.getConstraint();

    /*
     * As a convenience, set the weights appropriately since these values are
     * almost always used in tandem with the given Fill. The caller can always
     * call the weight(...) method later if these defaults aren't desired. 
     */
    switch (fill)
    {
      case HORIZONTAL:
        this.weightx = 1;
        this.weighty = 0;
        break;
      case VERTICAL:
        this.weightx = 0;
        this.weighty = 1;
        break;
      case BOTH:
        this.weightx = 1;
        this.weighty = 1;
        break;
      default:
        this.weightx = 0;
        this.weighty = 0;
        break;
    }

    return this;
  }

  public GBConstraints insets(int length)
  {
    return insets(length, length, length, length);
  }

  public GBConstraints insets(int top, int left, int bottom, int right)
  {
    this.insets = new Insets(top, left, bottom, right);
    return this;
  }

  public GBConstraints ipad(int ipadX, int ipadY)
  {
    this.ipadx = ipadX;
    this.ipady = ipadY;
    return this;
  }

  public GBConstraints span(int gridWidth, int gridHeight)
  {
    this.gridwidth = gridWidth;
    this.gridheight = gridHeight;
    return this;
  }

  public GBConstraints spanX(int gridWidth)
  {
    this.gridwidth = gridWidth;
    return this;
  }

  public GBConstraints spanY(int gridHeight)
  {
    this.gridheight = gridHeight;
    return this;
  }

  public GBConstraints weight(double weightX, double weightY)
  {
    this.weightx = weightX;
    this.weighty = weightY;
    return this;
  }

  public GBConstraints weightX(double weightX)
  {
    this.weightx = weightX;
    return this;
  }

  public GBConstraints weightY(double weightY)
  {
    this.weighty = weightY;
    return this;
  }
}

3)总而言之,这是一个演示如何使用上述类的演示。这大大简化了使用GridBagLayout,恕我直言。旁注:我通常远离静态导入,但在这种情况下我喜欢它。

演示:

package gbl;

import static gbl.Anchor.*;
import static gbl.Fill.*;

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

public class GridBagDemo implements Runnable
{
  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new GridBagDemo());
  }

  public void run()
  {
    JLabel lblFirst  = new JLabel("First Name");
    JLabel lblLast   = new JLabel("Last Name");
    JLabel lblStreet = new JLabel("Street");
    JLabel lblCity   = new JLabel("City");
    JLabel lblState  = new JLabel("State");
    JLabel lblZip    = new JLabel("ZIP");
    JLabel lblNotes  = new JLabel("Notes");

    JTextField txfFirst  = new JTextField(15);
    JTextField txfLast   = new JTextField(20);
    JTextField txfStreet = new JTextField(40);
    JTextField txfCity   = new JTextField(15);
    JTextField txfState  = new JTextField(5);
    JTextField txfZip    = new JTextField(10);

    JTextArea txaNotes = new JTextArea(5, 50);
    JScrollPane scrNotes = new JScrollPane(txaNotes);
    scrNotes.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

    Component spacer1 = Box.createHorizontalStrut(5);
    Component spacer2 = Box.createHorizontalStrut(5);

    JPanel panel = new JPanel(new GridBagLayout());
    panel.add(spacer1,   new GBConstraints(0,0));
    panel.add(lblFirst,  new GBConstraints(0,1));
    panel.add(txfFirst,  new GBConstraints(1,1));
    panel.add(lblLast,   new GBConstraints(2,1));
    panel.add(txfLast,   new GBConstraints(3,1).spanX(3).fill(HORIZONTAL));
    panel.add(lblStreet, new GBConstraints(0,2));
    panel.add(txfStreet, new GBConstraints(1,2).spanX(5).fill(HORIZONTAL));
    panel.add(lblCity,   new GBConstraints(0,3));
    panel.add(txfCity,   new GBConstraints(1,3));
    panel.add(lblState,  new GBConstraints(2,3).anchor(EAST));
    panel.add(txfState,  new GBConstraints(3,3));
    panel.add(lblZip,    new GBConstraints(4,3));
    panel.add(txfZip,    new GBConstraints(5,3).fill(HORIZONTAL));
    panel.add(lblNotes,  new GBConstraints(0,4));
    panel.add(scrNotes,  new GBConstraints(1,4).spanX(5).fill(BOTH));
    panel.add(spacer2,   new GBConstraints(0,5));

    JFrame frame = new JFrame("Grid Bag Demo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(new JScrollPane(panel), BorderLayout.CENTER);
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}

同样,这只是您在网上找到的众多方式之一。希望这会有所帮助。

答案 1 :(得分:2)

你说:

  

我这样称呼它:

Insets insets = new Insets(0,0,0,0);
JFrame frame = new JFrame();
label = new JLabel("Blablablah");   
addComponent(frame, label, 0,0, 1,1, 0,0, 0.5f,0, HORIZ, CENTER, insets);

你真的省略了frame.setLayout(new GridBagLayout())吗? 因为这是导致cannot add to layout: constraint must be a string (or null)错误的原因......

修改
可能重复:

答案 2 :(得分:0)

正如我上面评论的那样,@ ccjmme的帮助让我添加了两行并修改了签名以获得没有全局变量的工作版本。我发布的版本比工作版本要好得多。我随后的评论解释了原因。

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

public class Test{

  public static void addComponent(Component c, Container f,      GridBagConstraints gbc, 
                                    int     x,        int   y, 
                                    int     w,        int   h, 
                                    int     ipadx,    int   ipady, 
                                    float   wtx,      float wty,
                                    int fill, int anchor, Insets insets){
    if(fill   <= 0)     fill    = GridBagConstraints.NONE;
    if(anchor <= 0)     anchor  = GridBagConstraints.CENTER;
    if(insets == null)  insets  = new Insets(0,0,0,0);
    gbc.gridx = x;        gbc.gridy = y;      
    gbc.gridwidth = w;    gbc.gridheight = h;     
    gbc.fill = fill; 
    gbc.ipadx = ipadx;    gbc.ipady = ipady;  
    gbc.insets = insets;  gbc.anchor = anchor; 
    gbc.weightx = wtx;    gbc.weighty = wty;

    f.add(c,gbc);
  }

  public static void addComponent(String s, Container f, GridBagConstraints gbc, 
                                  int     x,        int   y, 
                                  int     w,        int   h, 
                                  int     ipadx,    int   ipady, 
                                  float   wtx,      float wty,
                                  int fill, int anchor, Insets insets){
    addComponent(new JLabel(s),f,gbc,x,y,w,h,ipadx,ipady,wtx,wty,fill,anchor,insets);
  }  

  public static void addComponent(Component c, Container f, GridBagConstraints gbc, 
                                  int     x,        int   y){
    addComponent(c, f, gbc, x, y, 1,1, 0,0, 0.5f,0.5f, 
                  GridBagConstraints.NONE, GridBagConstraints.CENTER,
                  new Insets(0,0,0,0));
  }


  public static void main(String[] args) {
    Insets insets = new Insets(0,0,0,0);
    JFrame frame = new JFrame();
    frame.setLayout(new GridBagLayout());
    JLabel label = new JLabel("Blablablah");
    JTextField text = new JTextField("text");
    JTextField next = new JTextField("a bit longer");
    GridBagConstraints gbc = new GridBagConstraints();

    addComponent("On the fly", frame, gbc, 0,0, 1,1, 0,0, 0.5f,0, 0, 0, insets);
    addComponent(label,        frame, gbc, 0,1);

    addComponent(next, frame, gbc, 1,1, 10,1, 0,0, 5.0f,0.5f, GridBagConstraints.EAST, 0, null);        
    addComponent(text, frame, gbc, 1,0);
    frame.pack();
    frame.setVisible(true);
  }
}

改进:

(1)addComponent的两个额外签名,以便(i)可以在不声明和初始化变量的情况下即时创建标签(如果代码需要引用它,则不好,但我很少这样做) (ii)只需指定(x,y)并接受默认值即可添加任何组件。

(2)“默认0”选项,以避免必须键入'GridBagConstraints.CENTER and ... NONE`,如果您通常需要填充和锚定值。

答案 3 :(得分:0)

这是我使用@ Splungebob的枚举和方法(以及他的“演示”作为模型),以非常轻松快速的方式设计和实现一个非常好的用户界面到我现有的具有可怕UI的程序中。

public class UI extends JFrame {
...
JPanel panel = new JPanel(new GridBagLayout());
panel.setBackground(Color.LIGHT_GRAY);
panel.add(lblCenterX,     new GBConstraints(0,0));
panel.add(lblCenterY,     new GBConstraints(0,1));
panel.add(lblRadius,      new GBConstraints(0,2).anchor(EAST));
panel.add(lblIterations,  new GBConstraints(0,3).anchor(EAST));
panel.add(spnCenterX,     new GBConstraints(1,0).fill(HORIZONTAL));
panel.add(spnCenterY,     new GBConstraints(1,1).ipad(90,10));
panel.add(spnRadius,      new GBConstraints(1,2));
panel.add(spnIterations,  new GBConstraints(1,3));
panel.add(btnPaint,       new GBConstraints(0,4).spanX(2).spanY(2).ipad(30,20).anchor(CENTER));
panel.add(btnDefaults,    new GBConstraints(0,6));
panel.add(btnExit,        new GBConstraints(1,6).anchor(EAST));
this.add(panel, BorderLayout.CENTER);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);

我发布这篇文章的唯一原因是希望有人像我对GBL那样需要尽可能多的帮助找到它,然后回头看看Splunge的东西。 btnPaint的行有多酷,我在那里制作了一个巨大的按钮!