在写界面的时候布局可谓是个头疼的问题,有的布局方式在一个系统里有,而在另外一个里面就没有,这就是很坑爹的一件事。比如说swing就有BorderLayout,而SWT偏偏又没有,在使用SWT的时候就只能恨恨了。之前在做课程设计的时候恰好在一本书上看到在SWT下自定义的BorderLayout,今天写出来分享分享。
直接上代码
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
public class BorderLayout extends Layout {
// 存放在不同位置的5个控件
private Control north;
private Control south;
private Control east;
private Control west;
private Control center;
@Override
protected Point computeSize(Composite composite, int wHint, int hHint,
boolean flushCache) {
// TODO Auto-generated method stub
getControls(composite);
// 定义面板的宽和高
int width = 0, height = 0;
// 计算面板的宽度
width += west == null ? 0 : getSize(west, flushCache).x;
width += east == null ? 0 : getSize(east, flushCache).x;
width += center == null ? 0 : getSize(center, flushCache).x;
// 如果上部和下部有控件,则宽度取较大的值
if (north != null) {
width = Math.max(width, getSize(north, flushCache).x);
}
if (south != null) {
width = Math.max(width, getSize(south, flushCache).x);
}
// 计算面板的高度
height += north == null ? 0 : getSize(north, flushCache).y;
height += south == null ? 0 : getSize(south, flushCache).y;
int heightCenter = center == null ? 0 : getSize(center, flushCache).y;
if (west != null) {
heightCenter = Math.max(heightCenter, getSize(west, flushCache).y);
}
if (east != null) {
heightCenter = Math.max(heightCenter, getSize(east, flushCache).y);
}
height += heightCenter;
// 计算的宽和高与默认的宽和高比较,返回较大值
return new Point(Math.max(width, wHint), Math.max(height, hHint));
}
@Override
protected void layout(Composite composite, boolean flushCache) {
// TODO Auto-generated method stub
getControls(composite);
// 获取当前面板可显示的区域
Rectangle rect = composite.getClientArea();
int left = rect.x, right = rect.width, top = rect.y, bottom = rect.height;
// 将各个控件放置到面板中
if (north != null) {
Point pt = getSize(north, flushCache);
north.setBounds(left, top, rect.width, pt.y);
top += pt.y;
}
if (south != null) {
Point pt = getSize(south, flushCache);
south.setBounds(left, rect.height - pt.y, rect.width, pt.y);
bottom -= pt.y;
}
if (east != null) {
Point pt = getSize(east, flushCache);
east.setBounds(rect.width - pt.x, top, pt.x, (bottom - top));
right -= pt.x;
}
if (west != null) {
Point pt = getSize(west, flushCache);
west.setBounds(left, top, pt.x, (bottom - top));
left += pt.x;
}
if (center != null) {
center.setBounds(left, top, (right - left), (bottom - top));
}
}
/**
* 计算某一控件当前的大小
*
* @param control
* @param flushCache
* @return
*/
protected Point getSize(Control control, boolean flushCache) {
return control.computeSize(SWT.DEFAULT, SWT.DEFAULT, flushCache);
}
/**
* 设置该类中每个位置控件的属性
*
* @param composite
*/
protected void getControls(Composite composite) {
// 获取当前面板中所有的控件对象
Control[] children = composite.getChildren();
// 将每个控件所放的位置对号入座
for (int i = 0; i < children.length; i++) {
Control child = children[i];
BorderData borderData = (BorderData) child.getLayoutData();
if (borderData.region == SWT.TOP)
north = child;
else if (borderData.region == SWT.BOTTOM)
south = child;
else if (borderData.region == SWT.RIGHT)
east = child;
else if (borderData.region == SWT.LEFT)
west = child;
else
center = child;
}
}
}
上面是布局Layout,还需要一个设置属性的。
import org.eclipse.swt.SWT;
public final class BorderData {
public int region = SWT.CENTER;//默认为中间
public BorderData(){
}
public BorderData(int region){
this.region = region;
}
}
使用举例:
Composite c = new Composite(parent, SWT.NONE);
c.setLayout(new BorderLayout());
Composite c2 = new Composite(c, SWT.NONE);
c2.setLayoutData(new BorderData(SWT.TOP));
这样就可以显示在父控件的顶部了。
但是这样还不够,用过BorderLayout的人就会发现,上面这种情况在顶部显示的控件高度不能控制,这样对于有些情况就不适用了。
所以下面给出一个比例布局,可以设置两个控件的比例。
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Layout;
/**
* 按比例布局两个控件
*
* @author Michael
*
*/
public class RatioLayout extends Layout {
private int orientation = SWT.HORIZONTAL;// 默认横向布局
public float ratio = 1.0f;
private Control control1;
private Control control2;
public RatioLayout() {
}
public RatioLayout(int orientation) {
this.orientation = orientation;
}
@Override
protected Point computeSize(Composite composite, int wHint, int hHint,
boolean flushCache) {
// TODO Auto-generated method stub
return new Point(wHint, hHint);
}
@Override
protected void layout(Composite composite, boolean flushCache) {
// TODO Auto-generated method stub
getControls(composite);
// 当前面板的可显示区域
Rectangle rect = composite.getClientArea();
int x = rect.x, y = rect.y, width = rect.width, height = rect.height;
if (orientation == SWT.HORIZONTAL) {// 横向布局
if (control1 != null) {
control1.setBounds(x, y, (int) (width * ratio), height);
}
if (control2 != null) {
control2.setBounds((int) (width * ratio), y,
(int) (width * (1 - ratio)), height);
}
}
if (orientation == SWT.VERTICAL) {// 纵向布局
if (control1 != null) {
control1.setBounds(x, y, width, (int) (height * ratio));
}
if (control2 != null) {
control2.setBounds(x, (int) (height * ratio), width, (int) (height * (1 - ratio)));
}
}
}
// 获取所有控件对象
protected void getControls(Composite composite) {
Control[] children = composite.getChildren();
if (children.length > 2) {
return;
}
try {
control1 = children[0];
control2 = children[1];
} catch (ArrayIndexOutOfBoundsException e) {
// TODO: handle exception
return;
}
}
}
上面这种方式只能容纳两个控件,使用方式如下:
RatioLayout ratioLayout = new RatioLayout(SWT.VERTICAL);
ratioLayout.ratio = 0.2f;
好了,就介绍这两种布局。