Looking for general method for GridBagLayout component creation

假装没事ソ 提交于 2019-11-27 02:17:18

I use GridBagLyout quite a lot, but like many others before me, I quickly found out it can be quite verbose. There are many examples on the web of how users wrote utility methods and/or classes to help them generate GBL code. I'll show you what I do.

1) First, I created 2 enums that are wrappers for the anchor and fill GridBagConstraints fields. I prefer the type checking of enums vs. ints, and it also allows me to write more concise code (as you'll see later). And yes, I still use the older "directional" values for Anchor. I could never quite get used to the preferred values of PAGE_START and the like. Use whatever you prefer.

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) Then, I created a subclass of GridBagConstraints that allowed me "chain" the properties only as I need them, while utilizing common defaults:

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) Putting it all together, here's a demo that shows how to use the above classes. This greatly simplifies using GridBagLayout, IMHO. Side note: I normally stay away from static imports, but I like it in this situation.

Demo:

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);
  }
}

Again, this is just one of many ways you'll find online. Hope this helps.

ccjmne

You said:

I called it like so:

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);

Did you actually omit frame.setLayout(new GridBagLayout())?
Because this is what causes the cannot add to layout: constraint must be a string (or null) error...

EDIT:
Possible duplicates:

As I commented above, @ccjmme's help led me to add two lines and modify a signature to get a working version with no global variables. I am posting a version that is much better than that working verion. My subsequent comment explains why.

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);
  }
}

Improvements:

(1) Two additional signatures for addComponent so that (i) a label can be created on the fly without declaring and initializing a variable (not good if code needs to refer to it, but mine rarely does) and (ii) any component can be added by just specifying (x,y) and accepting defaults.

(2) "Default 0" options to avoid having to type 'GridBagConstraints.CENTERand...NONE` if you'll usually want those fill and anchor values.

Here's me using @Splungebob's enums and methods (and his "demo" as a model) to positively painlessly and quickly design and implement a very nice UI into an existing program of mine that had a terrible 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);

I post this only in hopes that someone needing as much help as I did about GBL finds it and then looks back up at Splunge's stuff. How cool is the line for btnPaint, where I make a HUGE button!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!