java - 寻找 GridBagLayout 组件创建的通用方法

标签 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) 收到消息“无法添加到布局:约束必须是字符串(或空值)” .

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

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

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

然后我像这样修改了问题行:

frame.add(c, gbc);

所以我使用了一个全局变量,frame ,当我宁愿将其作为参数传递时。

两个问题:

(1) 有没有办法对我的代码进行最低限度的修改以允许传递 frameaddComponent

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


附言这是对修改后的 addComponent 的调用, 匆忙拼凑起来以获得我想要的前几行的一些相似之处。间距现在很臭——我需要用 insets、ipad、fills 来捣乱——但它实际上是可用的。 (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 个枚举,它们是 anchorfill GridBagConstraints 字段的包装器。与 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;
  }
}

填充.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);
  }
}

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

关于java - 寻找 GridBagLayout 组件创建的通用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21010799/

相关文章:

java - 自定义布局 Java Swing

java - JTextPane - 使插入符号正常大小?

java - 如何在 JPanel 和 JFrame 范围内绘图?

java - 如何修复日期转换时的 'JsonSyntaxException'

Java 同步块(synchronized block)

java - 在 Java 中创建网格

java - 在 GridBagLayout 中的组件之间放置空间

java - 如何在 JButton 单击时更新/刷新 JPanel?

java - 消费者生产者错误中的意外输出

java - 如何访问android中的下载文件夹?