寻找用于GridBagLayout组件创建的通用方法 [英] Looking for general method for GridBagLayout component creation

查看:80
本文介绍了寻找用于GridBagLayout组件创建的通用方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm designing a GUI with 20 or so components: 10 labels, 4 text fields, 4 buttons, and 2 text areas. Using GridBagLayout seemed a great idea. But with all the instance variables required to do it by the book for each component (i.e., not reuse), a general method for adding components seemed a must. I really thought this could work:

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

(Note: HORIZ is abbreviation for GridBagConstraints.HORIZONTAL; CENTER is abbreviation for 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)".

But I got message "cannot add to layout: constraint must be a string (or null)" at f.add(c.gbc).

我想我理解错误:frame在方法的第一行中调用addComponentgbc之前没有GridBagConstraints不属于参数f(或还有其他吗?).

I think I understand the error: frame doesn't have GridBagConstraints prior to the call to addComponent and gbc in the first line of the method doesn't belong to parameter f (or anything else?).

因此我略微修改了方法签名,省略了Container:

So I modified the method signature slightly, omitting Container:

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

我这样修改了问题行:

frame.add(c, gbc);

因此,当我希望将其作为参数传递时,我正在使用全局变量frame.

So I'm using a global variable, frame, when I'd rather pass it as an argument.

两个问题:

(1)是否可以最小化修改我的代码以允许将frame传递给addComponent?

(1) Is there a way to minimally modify my code to enable passing frame to addComponent?

(2)是否有任何理由要这样做?我想这等于问,你会怎么做?

(2) Is there any reason to want to do so? I guess this amounts to asking, what would YOU do?

P.S.这是对修改后的addComponent的调用,这些调用匆忙组合在一起以使我所要的前几行看起来有些相似.此刻的间距很小-我需要用插图,ipads和填充物胡闹-但它实际上是可用的. (frame的新名称是GUI.)

P.S. Here's calls to the modified addComponent, hastily thrown together to get some semblance of the first few lines of what I want. The spacing reeks at the moment--I need to monkey with insets, ipads, fills--but it's actually usable. (New name for frame is 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代码.我会告诉你我做什么.

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)首先,我创建了两个枚举,它们分别是 anchor fill GridBagConstraints字段的包装.我更喜欢枚举与整数的类型检查,这也使我可以编写更简洁的代码(稍后将看到).是的,我仍然使用较旧的方向"值作为锚点".我永远无法完全习惯PAGE_START之类的首选值.使用您喜欢的任何东西.

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)然后,我创建了GridBagConstraints的子类,该子类允许我仅在需要它们时就链接"属性,同时利用常见的默认值:

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)放在一起,这是一个演示如何使用上述类的演示.这大大简化了IMHO的GridBagLayout的使用.旁注:我通常不使用静态导入,但是在这种情况下我喜欢它.

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.

演示:


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.

这篇关于寻找用于GridBagLayout组件创建的通用方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆