上文自定义布局管理器-FormLayout介绍了FormLayout的参考实现,利用FormLayout,通过指定left、top、
right(可选)、bottom(可选)布局约束可以对组件进行精确定位。然而有些组件在业务上是有固定尺寸的,例如自定义组件之Button介绍的一样,通过给按钮指定4种状态时的图片,那么组件的最佳尺寸就是图片的尺寸,因此组件的PreferredSize就可以确定,所以此时只需要组件中心的确定坐标就可以了,实际组件的Location只和其PreferredSize有关。如下图所示:
这就是CenterLayout的思想。
修改FormData,只需要添加两个变量即可。
public class FormData {
public FormAttachment left;
public FormAttachment right;
public FormAttachment top;
public FormAttachment bottom;
public FormAttachment centerX;
public FormAttachment centerY;
}
CenterLayout与FormLayout不同只在于addLayoutComponent、layoutContainer这两个
方法实现,其他接口方法均相同,所以下面只介绍这两个方法实现,其他接口方法请
参阅上文自定义布局管理器-FormLayout
在addLayoutComponent方法的开头,同样是对布局约束参数constraints合法性进行检查,这点与FormLayout大致相同。
if (constraints == null) {
throw new IllegalArgumentException("constraints can't be
null");
} else if (!(constraints instanceof FormData)) {
throw new IllegalArgumentException("constraints must be a"
+ FormData.class.getName() + "instance");
} else {
......
}
进行空值判断和类型判断。然后在else块中的代码如下:
synchronized (comp.getTreeLock()) {
FormData formData = (FormData) constraints;
if (formData.centerX == null || formData.centerY == null) {
throw new IllegalArgumentException(
"centerX FormAttachment and centerY
FormAttachment can't be null");
} else if (comp.getPreferredSize() == null) {
throw new RuntimeException(
"component must have preferred size before be
add into parent with CenterLayout");
}
componentMap.put(comp, (FormData) constraints);
}
对于CenterLayout来说,FormData对象的centerX、centerY必须给出,因为它代表,点的坐标,除此之外组件必须有PreferredSize属性来指定组件大小。
layoutContainer方法实现也大致相同
public synchronized void layoutContainer(Container target) {
synchronized (target.getTreeLock()) {
int w = target.getWidth();
int h = target.getHeight();
Component[] components = target.getComponents();
for (Component component : components) {
FormData formData = componentMap.get(component);
if (formData != null) {
......
}
}
}
}
上面这步与FormLayout一样。关键在if语句块内,代码如下:
FormAttachment centerX = formData.centerX;
FormAttachment centerY = formData.centerY;
int width = component.getPreferredSize().width;
int height = component.getPreferredSize().height;
int x = (int) (centerX.percentage * w) + centerX.offset
- width
/ 2;
int y = (int) (centerY.percentage * h) + centerY.offset
- height / 2;
component.setBounds(x, y, width, height);
获得centerX、centerY以及最佳尺寸,如上图所示,不难得出x、y的计算方法。
至此,自定义布局管理器就介绍到这里,这两个布局类可以解决很多静态布局需求,所谓静态布局是指容器内有什么组件是固定的。如果遇到动态界面,例如组件的内容依照用户级别、插件扩展点等因素决定,也并不是难事,因为了解了布局管理器运行机制以后可很容易地定义适合你需求的布局类。对于静态布局来说,你可能厌倦了hard coding来布局,你希望这一切由xml这样的配置搞定,好,下一部分则开始“压轴戏”——用配置文件解决布局。