寻找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)”。

我想我理解错误:在调用addComponent之前frame没有GridBagConstraints ,并且方法的第一行中的gbc不属于参数f (或其他任何东西?)。

所以我略微修改了方法签名,省略了Container

 public static void addComponent( Component c, int x, int y, ... (rest unchanged) 

我像这样修改了问题行:

 frame.add(c, gbc); 

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

两个问题:

(1)有没有办法最小化修改我的代码以启用将frame传递给addComponent

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


PS这里是对修改后的addComponent的调用,匆匆扔在一起,以获得我想要的前几行的一些相似之处。 此刻的间距很大 – 我需要用插图,ipads,填充来实现 – 但它实际上是可用的。 ( frame新名称是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)); 

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

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

Anchor.java:

包gbl;

 import java.awt。*;

 / **
  *便利枚举,将所有可能的值别名化
  * GridBagConstraints 属性。
  * /
 public enum Anchor
 {
   NORTH(GridBagConstraints.NORTH)
  南(GridBagConstraints.SOUTH)
   EAST(GridBagConstraints.EAST)
   WEST(GridBagConstraints.WEST)
  东北(GridBagConstraints.NORTHEAST)
  西北(GridBagConstraints.NORTHWEST)
  东南(GridBagConstraints.SOUTHEAST)
  西南(GridBagConstraints.SOUTHWEST)
  中心(GridBagConstraints.CENTER);

   private int约束;

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

   public int getConstraint()
   {
    回归约束;
   }
 }

Fill.java:

包gbl;

 import java.awt。*;

 / **
  *便利枚举,将所有可能的值别名化
  * GridBagConstraints 填充属性。
  * /
 public enum Fill
 {
   NONE(GridBagConstraints.NONE)
  水平(GridBagConstraints.HORIZONTAL)
  垂直(GridBagConstraints.VERTICAL)
   BOTH(GridBagConstraints.BOTH);

   private int约束;

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

   public int getConstraint()
   {
    回归约束;
   }
 }

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

GBConstraints.java:

包gbl;

 import java.awt。*;

 / **
  *便捷类,简化GridBagConstraints对象的创建。
  * /
公共类GBConstraints扩展了GridBagConstraints
 {
   public GBConstraints(int gridX,int gridY)
   {
    超();

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

     this.gridwidth = 1;
     this.gridheight = 1;
     this.weightx = 0;
     this.weighty = 0;
     this.anchor = NORTHWEST;  //旧的默认值是CENTER
     this.fill = NONE;
     this.insets = new Insets(1,2,1,2);  //旧的默认值是(0,0,0,0)
     this.ipadx = 1;  //旧默认值为0
     this.ipady = 1;  //旧默认值为0
   }

   public GBConstraints anchor(Anchor anchor)
   {
     this.anchor = anchor.getConstraint();
    归还这个;
   }

  公共GBConstraints填充(填充填充)
   {
     this.fill = fill.getConstraint();

     / *
      *为方便起见,请适当设置权重,因为这些值是
      *几乎总是与给定的填充一起使用。 来电者可以随时
      *如果不需要这些默认值,请稍后调用weight(...)方法。 
      * /
    开关(填充)
     {
      案件HORIZONTAL:
         this.weightx = 1;
         this.weighty = 0;
        打破;
      案例VERTICAL:
         this.weightx = 0;
         this.weighty = 1;
        打破;
      案例:
         this.weightx = 1;
         this.weighty = 1;
        打破;
      默认:
         this.weightx = 0;
         this.weighty = 0;
        打破;
     }

    归还这个;
   }

   public GBConstraints insets(int length)
   {
    返回插图(长度,长度,长度,长度);
   }

   public GBConstraints insets(int top,int left,int bottom,int right)
   {
     this.insets = new Insets(top,left,bottom,right);
    归还这个;
   }

   public GBConstraints ipad(int ipadX,int ipadY)
   {
     this.ipadx = ipadX;
     this.ipady = ipadY;
    归还这个;
   }

   public GBConstraints span(int gridWidth,int gridHeight)
   {
     this.gridwidth = gridWidth;
     this.gridheight = gridHeight;
    归还这个;
   }

   public GBConstraints spanX(int gridWidth)
   {
     this.gridwidth = gridWidth;
    归还这个;
   }

   public GBConstraints spanY(int gridHeight)
   {
     this.gridheight = gridHeight;
    归还这个;
   }

  公共GBConstraints重量(double weightX,double weightY)
   {
     this.weightx = weightX;
     this.weighty = weightY;
    归还这个;
   }

   public GBConstraints weightX(double weightX)
   {
     this.weightx = weightX;
    归还这个;
   }

   public GBConstraints weightY(double weightY)
   {
     this.weighty = weightY;
    归还这个;
   }
 }

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

演示:

包gbl;

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

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

公共类GridBagDemo实现了Runnable
 {
   public static void main(String [] args)
   {
     SwingUtilities.invokeLater(new GridBagDemo());
   }

   public void run()
   {
     JLabel lblFirst =新的JLabel(“名字”);
     JLabel lblLast =新的JLabel(“姓氏”);
     JLabel lblStreet =新JLabel(“街头”);
     JLabel lblCity =新JLabel(“城市”);
     JLabel lblState = new JLabel(“State”);
     JLabel lblZip =新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);

    组件spacer1 = Box.createHorizo​​ntalStrut(5);
    组件spacer2 = Box.createHorizo​​ntalStrut(5);

     JPanel面板=新的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(真);
   }
 }

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

你说:

我这样打电话:

 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)错误…

编辑:
可能重复:

  • Java GridBagLayout和JPanel错误:无法添加到布局:约束必须是字符串(或null)
  • 获取exception:java.lang.IllegalArgumentException:无法添加到布局:约束必须是字符串(或null)

正如我上面评论的那样,@ 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`,如果您通常需要那些填充和锚点值。

这是我使用@ Splungebob的枚举和方法(以及他的“演示”作为模型),以非常轻松快速的方式设计和实现一个非常好的UI到我现有的具有可怕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的线路有多酷,我在那里制作了一个巨大的按钮!