14.12 自定义布局
在SWT中,用户可以通过setLayout设置组件的布局信息。布局对象会根据父组件的大小和子组件的布局信息计算出每个子组件的位置和大小,使整个布局空间符合用户的需求。下面将介绍如何创建自己的布局类,实现用户自定义的布局。
14.12.1 Layout类
在SWT中,所有的布局类都继承于Layout抽象类。Layout有两个抽象方法:
l computeSize (Composite composite, int wHint, int hHint, boolean flushCache)
l layout (Composite composite, boolean flushCache)
computeSize方法负责计算组件所有子组件所占的高度和宽度,并返回一个Point类型的变量(width,height)。layout方法负责计算子组件的大小和位置,并按计算出来的位置排列子组件。
14.12.2 创建自己的布局类
如果用户希望组件按自己的方式进行布局,可以创建自己的布局类,实现自己的布局。要实现自己的布局,用户要继承Layout类,并实现layout方法和computeSize方法。下面将实现一个简单的按列进行布局的布局类,在此布局中,所有的子组件将按一列显示,并且子组件的宽度相等,代码如例程14-17所示。
例程14-17 ColumnLayout.java
public class ColumnLayout extends Layout {
public static final int MARGIN = 4;
public static final int SPACING = 2;
Point [] sizes;
int maxWidth, totalHeight;
protected Point
computeSize(Composite composite, int wHint, int hHint,
boolean flushCache) {
Control children[] = composite.getChildren();
if (flushCache || sizes == null || sizes.length != children.length) {
initialize(children);
}
int width = wHint, height = hHint;
if (wHint == SWT.DEFAULT) width = maxWidth;
if (hHint == SWT.DEFAULT) height = totalHeight;
return new Point(width + 2 * MARGIN, height + 2 * MARGIN);
}
protected void layout(Composite composite, boolean flushCache) {
Control children[] = composite.getChildren();
if (flushCache || sizes == null || sizes.length != children.length) {
initialize(children);
}
Rectangle rect = composite.getClientArea();
int x = MARGIN, y = MARGIN;
//计算最大宽度
int width = Math.max(rect.width - 2 * MARGIN, maxWidth);
for (int i = 0; i < children.length; i++) {
int height = sizes[i].y;
//设置子组件的位置
children[i].setBounds(x, y, width, height);
//计算当前组件的y轴的坐标
y += height + SPACING;
}
}
void initialize(Control children[]) {
maxWidth = 0;
totalHeight = 0;
sizes = new Point [children.length];
for (int i = 0; i < children.length; i++) {
//计算子组件的大小
sizes[i] = children[i].computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
maxWidth = Math.max(maxWidth, sizes[i].x);
totalHeight += sizes[i].y;
}
totalHeight += (children.length - 1) * SPACING;
}
}
在ColumnLayout类中,通过layout方法对子组件重新计算位置,并设置子组件的位置。为了验证ColumnLayout类,下面通过ColumnLayoutTest类测试ColumnLayout类的效果,代码如例程14-18所示。
例程14-18 ColumnLayoutTest.java
public class ColumnLayoutTest {
static Shell shell;
static Button button3;
public static void main(String[] args) {
Display display = new Display();
shell = new Shell(display);
shell.setLayout(new ColumnLayout());
new Button(shell, SWT.PUSH).setText("B1");
new Button(shell, SWT.PUSH).setText("Very Wide Button 2");
(button3 = new Button(shell, SWT.PUSH)).setText("Button 3");
new Text(shell, SWT.NONE).setText("text");
Button grow = new Button(shell, SWT.PUSH);
grow.setText("Grow Button 3");
// 添加选择组件监听器
grow.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
button3.setText("Extreemely Wide Button 3");
//组件大小改变后通知父组件进行重新布局
shell.layout();
shell.pack();
}
});
Button shrink = new Button(shell, SWT.PUSH);
shrink.setText("Shrink Button 3");
shrink.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
button3.setText("Button 3");
//组件大小改变后通知父组件进行重新布局
shell.layout();
shell.pack();
}
});
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
}
}
当选择“Grow Button 3”组件后,layout方法会根据子组件的最大宽度调整所有子组件的宽度,程序运行效果如图14-10所示。

原始大小 宽度改变后
图14-10 自己定义布局






