7.1 布局管理器概述
FillLayout(充满式布局):在单行或单列中放置相同大小的控件,是最简单的布局。
RowLayout(行列式布局):在单行或者多行中放置控件,应用了fill、wrap和spacing等选项。
GridLayout(网格式布局):向表格一样放置控件。
FormLayout(表格式布局):与GridLayout功能差不多的布局,可以通过定义4个边的“附加值”来放置控件。
StackLayout(堆栈式布局):类似堆栈式的布局,只显示最上方的控件。
7.2 FillLayout(充满式布局)
规则:试图填充一行或一列,尽可能的充满整个面板,并且强制所有控件平均分配大小。FillLayout不会自动执行,也不能设置每个控件之间的空隙,但能够指定面板的四周的空白。
FillLayout layout = new FillLayout(SWT.VERTICAL);
或
FillLayout layout = new FillLayout();
layout.type = SWT.VERTICAL; // 默认为:SWT.HORIZONTAL
水平填充(SWT.HORIZONTAL):
垂直填充(SWT.VERTICAL):
设置四周补白:
FillLayout layout = new FillLayout();
layout.type=SWT.VERTICAL;
layout.marginHeight = 10; // 设置上下补白高度
layout.marginWidth = 20; // 设置左右
layout.spacing = 5; // 设置控件之间的空隙
shell.setLayout( layout );
显示效果:
7.3 RowLayout(行列式布局)
RowLayout填充控件时可以折行显示,并且可以使用RowData设置某一个指定控件的大小。
package www.swt.com.ch7;
import org.eclipse.swt.SWT;
public class RowLayoutSample {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
RowLayout layout = new RowLayout();
layout.type = SWT.HORIZONTAL;// 设置水平填充
layout.marginLeft = 5;// 左补白
layout.marginTop = 5;// 上补白
layout.marginRight = 5;// 右补白
layout.marginBottom = 5;// 下补白
layout.spacing = 2;// 控件的间隙
layout.wrap = true;// 是否折行显示
layout.pack = false;// false:控件平均分配大小
layout.justify = true;// 是否充满整个一行
shell.setLayout(layout);
new Button(shell, SWT.NONE).setText("B1");
new Button(shell, SWT.NONE).setText("Button2");
new Button(shell, SWT.NONE).setText("Wide Button3");
new Button(shell, SWT.NONE).setText("B4");
shell.layout();
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
显示效果:
设置控件的大小:
// layout.pack = false;// false:控件平均分配大小
Button b = new Button(shell, SWT.NONE);
b.setText("RowData");
b.setLayoutData(new RowData(100, 30));
显示效果:
设置是否等宽或等高:fill属性
当以水平方式填充时,fill属性试图使所用控件具有同样高度;当以垂直方式显示时,试图使用所有控件具有同样宽度。
水平填充,设置等高:layout.fill = true;
垂直填充,设置等宽:layout.fill = true;
7.4 GridLayout(网格式布局)
使用GridLayout布局,控件将会按照网格的方式进行填充。GridLayout所放置的控件可以有一个关联的布局数据对象GridData。GridLayout的强大功能在于,可以使用GridData为每一个控件设置不同的布局。
package www.swt.com.ch7;
import org.eclipse.swt.SWT;
public class GridLayoutSample {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 3; //设置网格的列数
gridLayout.makeColumnsEqualWidth = true; //设置网格等宽
gridLayout.verticalSpacing = 10;
gridLayout.horizontalSpacing = 10;
shell.setLayout(gridLayout);
new Button(shell, SWT.PUSH).setText("B1");
new Button(shell, SWT.PUSH).setText("Wide Button 2");
new Button(shell, SWT.PUSH).setText("Button 3");
new Button(shell, SWT.PUSH).setText("B4");
new Button(shell, SWT.PUSH).setText("Button 5");
new Button(shell, SWT.PUSH).setText("B6");
//GridData
Button button = new Button(shell, SWT.PUSH);
button.setText("GridData");
button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL|GridData.GRAB_HORIZONTAL));
Button b1 = new Button(shell, SWT.PUSH);
b1.setText("GridData2");
GridData gridData = new GridData();
// gridData.horizontalIndent = 20; // 缩进
gridData.horizontalSpan =2; // 水平跨越两个单元格
gridData.horizontalAlignment = SWT.FILL; //充满
b1.setLayoutData(gridData);
Button b2 = new Button(shell, SWT.PUSH);
b2.setText("GridData3");
GridData gridData2 = new GridData();
gridData2.horizontalSpan =2; // 水平跨越两个单元格
gridData2.verticalSpan = 2; // 垂直跨越两个单元格
gridData2.horizontalAlignment = SWT.FILL; //水平充满
gridData2.verticalAlignment = SWT.FILL; //垂直充满
gridData2.grabExcessHorizontalSpace = true; //设置水平抢占
gridData2.grabExcessVerticalSpace = true; //设置垂直抢占
gridData2.minimumHeight=100; //最小高度
gridData2.minimumWidth =100; //最小宽度
gridData2.widthHint=100; //设置宽度
gridData2.heightHint=100; //设置高度
b2.setLayoutData(gridData2);
shell.layout();
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
注意:不要重用GridData对象。每一个面板(Composite)对象中被GridLayout管理的控件必须有一个唯一的GridData对象。如果在设置布局时一个GridLayout中的控件的GridData为null,就会为它创建一个唯一的GridData对象。
注意:设置了widthHint和heightHint属性后只是在程序刚一运行时才会起作用,随着窗口的改变,会重新计算控件大小。
显示效果:
去掉下面两行后的效果:
gridData2.grabExcessHorizontalSpace = true; //设置水平抢占
gridData2.grabExcessVerticalSpace = true; //设置垂直抢占
按钮“GridData3”未随着窗口大小调整高度。
样式常量对照表
样式常量 <==> 对应属性值
GRAB_HORIZONTAL <==> grabExcessHorizontalSpace=true
GRAB_VERTICAL <==> grabExcellVerticalSpace=true
HORIZONTAL_ALIGN_BEGINNING <==> horizontalAlignment=SWT.BEGINNING
HORIZONTAL_ALIGN_CENTER <==> horizontalAlignment=SWT.CENTER
HORIZONTAL_ALIGN_END <==> horizontalAlignment=SWT.END
HORIZONTAL_ALIGN_FILL <==> horizontalAlignment=SWT.FILL
VERTICAL_ALIGN_BEGINNING <==> verticalAlignment=SWT.BEGINNING
VERTICAL_ALIGN_CENTER <==> verticalAlignment=SWT.CENTER
VERTICAL_ALIGN_END <==> verticalAlignment=SWT.END
VERTICAL_ALIGN_FILL <==> verticalAlignment=SWT.FILL
FILL_BOTH <==> horizontalAlignment=SWT.FILL + verticalAlignment=SWT.FILL
7.5 FormLayout(表格式布局)
FormLayout通过设置FormData四边的附加值(FormAttachment对象)来设置控件的布局。一个附加值让一个控件指定的一边附件到父面板容器类(Composite)的位置或者其他控件上。所以,这种布局可以指定某两个控件的相对位置,并且能随着窗口的改变而改变。
FormAttachment 的使用说明及示例参考:SWT 之 FormAttachment
7.6 StackLayout(堆栈式布局)
StackLayout堆栈式布局类似于选项卡(TabFolder),当前只显示最上方的控件。例如,面板上有10个文本框,面板设置为StackLayout布局,当单击“显示下一个文本框”按钮时,下一个文本框就显示出来,这样面板中始终只有一个文本框,设置最上方显示控件的属性是layout.topControl。
package www.swt.com;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class testStackLayout {
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout());
// 创建放置文本框的面板
final Composite parent = new Composite(shell, SWT.NONE);
// 设置面板的布局数据
parent.setLayoutData(new GridData(GridData.FILL_BOTH));
// 创建堆栈式布局
final StackLayout layout = new StackLayout();
// 将堆栈式布局应用于模板
parent.setLayout(layout);
// 创建10个文本框
final Text[] textArray = new Text[10];
for (int i = 0; i < textArray.length; i++) {
textArray[i] = new Text(parent, SWT.MULTI);
textArray[i].setText("这是第 " + i + " 个文本框");
}
// 设置堆栈中当前显示的控件
layout.topControl = textArray[0];
Button b = new Button(shell, SWT.PUSH);
b.setText("显示下一个文本框");
// 保存当前显示的文本框的索引值
final int[] index = new int[1];
// 为按钮添加单击事件
b.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event arg0) {
// 计算出下一个文本框的索引数
index[0] = (index[0] + 1) % textArray.length;
// 设置当前显示的控件
layout.topControl = textArray[index[0]];
// 重新刷新布局
parent.layout();
}
});
shell.setSize(200, 150);
shell.open();
shell.layout();
// shell.pack();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
显示效果:
点击按钮后:
7.7 自定义布局管理器
任何布局类都是Lyaout的子类,Layout是一个抽象类,源代码如下:
package org.eclipse.swt.widgets;
import org.eclipse.swt.graphics.*;
public abstract class Layout {
protected abstract Point computeSize (Composite composite, int wHint, int hHint, boolean flushCache);
protected boolean flushCache (Control control) {
return false;
}
protected abstract void layout (Composite composite, boolean flushCache);
}
创建一个自定义的布局类要继承Layout类,并且要实现Layout中的抽象方法。以下代码创建的是一个最简单的自定义类MyLayout:
package www.swt.com;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Layout;
public class MyLayout extends Layout {
// 该方法计算面板显示的大小
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
return new Point(wHint, hHint);
}
// 设置子控件的位置
protected void layout(Composite composite, boolean flushCache) {
}
}
Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache)方法:该方法是计算布局的大小,也就是按照一定的规则算法计算出最终布局的长和宽,其中wHint和hHint是设置默认的宽和高。例如:当计算出来的长和宽小于默认的宽和高时,就可以使用默认的宽和高。flushCache参数设置是否使用缓存的数据。
void layout(Composite composite, boolean flushCache)方法:该方法是对该面板(参数Composite)中所有的控件(Control)设置显示的具体位置,通常获得该面板中的所有控件的方法是composite.getChildren()。这样就可以根据指定的计算规则来放置每个控件的位置了。
综上所述,创建一个自定义布局关键是实现这两个方法,而具体布局的设置要根据设定的计算方法来实现。
布局计算的常用方法
1. 控件(Control)类中的常用方法
◆ 计算控件合适的大小的方法:Point computeSize(int wHint, int hHint)和Point computeSize(int wHint, int hHint, boolean changed)。例如:
Point point = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
int width = point.x;
int height = point.y;
◆ 获得控件当前坐标位置的方法:Rectangle getBounds()。例如:
Rectangle rect = control.getBounds();
int left = rect.x;
int right = rect.width;
int top = rect.y;
int bottom = rect.height;
◆ 设置控件位置的方法:setBounds(int x, int y, int width, int height)或setBounds(Rectangle rect)。
2. 面板(Composite)类中的常用方法
◆ 获得面板的大小区域的方法:Rectangle getClientArea()。
◆ 获得所有子控件的方法:Control[] getChildren()。
◆ 获得面板的布局对象:Layout getLayout()。
自定义布局类(BorderLayout)
BorderLayout布局将控件按东、南、西、北、中5个区域放置,每个方向最多只能放置一个控件,随着窗口大小的改变,整个窗口会不断撑大。
(1)创建一个BorderData类,该类设置控件所在位置。
package www.swt.com.ch7.testBorderLayout;
import org.eclipse.swt.SWT;
public final class BorderData {
public int region = SWT.CENTER; // 默认为中间
public BorderData() {
}
public BorderData(int region) {
this.region = region;
}
}
(2)编写最重要的BorderLayout类,该类的详细代码如下:
package www.swt.com.ch7.testBorderLayout;
import org.eclipse.swt.SWT;
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) {
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) {
Point pt = getSize(north, flushCache);
width = Math.max(width, pt.x);
}
if (south != null) {
Point pt = getSize(south, flushCache);
width = Math.max(width, pt.x);
}
// 计算面板的高度
height += north == null ? 0 : getSize(north, flushCache).y;
height += south == null ? 0 : getSize(south, flushCache).y;
int heightOther = center == null ? 0 : getSize(center, flushCache).y;
if (west != null) {
Point pt = getSize(west, flushCache);
heightOther = Math.max(heightOther, pt.y);
}
if (east != null) {
Point pt = getSize(east, flushCache);
heightOther = Math.max(heightOther, pt.y);
}
height += heightOther;
// 计算的宽和高与默认的宽和高作比较,返回之中较大的
return new Point(Math.max(width, wHint), Math.max(height, hHint));
}
@Override
protected void layout(Composite composite, boolean flushCache) {
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));
}
}
// 计算某一控件当前的大小,长和宽
protected Point getSize(Control control, boolean flushCache) {
return control.computeSize(SWT.DEFAULT, SWT.DEFAULT, flushCache);
}
// 设置该类中每个位置控件的属性的方法
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;
}
}
}
}
(3)最后创建一个测试类:
package www.swt.com.ch7.testBorderLayout;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class TestBorderLayout {
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(200, 150);
shell.setLayout(new BorderLayout());
Button buttonWest = new Button(shell, SWT.PUSH);
buttonWest.setText("左");
buttonWest.setLayoutData(new BorderData(SWT.LEFT));
Button buttonEast = new Button(shell, SWT.PUSH);
buttonEast.setText("右");
buttonEast.setLayoutData(new BorderData(SWT.RIGHT));
Button buttonNorth = new Button(shell, SWT.PUSH);
buttonNorth.setText("上");
buttonNorth.setLayoutData(new BorderData(SWT.TOP));
Button buttonSouth = new Button(shell, SWT.PUSH);
buttonSouth.setText("下");
buttonSouth.setLayoutData(new BorderData(SWT.BOTTOM));
Text text = new Text(shell, SWT.MULTI);
text.setText("中间");
text.setLayoutData(new BorderData());
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
显示效果:
拖放后的效果:
联系客服